package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sc.nft.config.hf.HfConfig;
import com.sc.nft.config.lianlian.LlConfig;
import com.sc.nft.config.sand.SandConfig;
import com.sc.nft.config.sand.SandPayUtil;
import com.sc.nft.dao.ExpenditureRecordDao;
import com.sc.nft.dao.GetMallOrderGrossProfitDTO;
import com.sc.nft.dao.MallMemberEquityTargetDao;
import com.sc.nft.dao.MallOrderBillDao;
import com.sc.nft.dao.MallOrderDao;
import com.sc.nft.dao.MallOrderExchangeDao;
import com.sc.nft.dao.MallOrderIncomeDao;
import com.sc.nft.dao.MallOrderStatusLogDao;
import com.sc.nft.dao.MallOrderUpdateAddressLogDao;
import com.sc.nft.dao.StaticDataDao;
import com.sc.nft.dao.SupplierManageBindingDao;
import com.sc.nft.dao.UserAssetsDao;
import com.sc.nft.dao.UserInfoDao;
import com.sc.nft.dao.UserWalletDao;
import com.sc.nft.dao.UserWalletDetailDao;
import com.sc.nft.dto.CheckProductHasPreemptionDTO;
import com.sc.nft.dto.MallActivitySpecsGetSendCodeDTO;
import com.sc.nft.dto.MallOrderBillGetBillStatusDTO;
import com.sc.nft.dto.MallOrderPushDTO;
import com.sc.nft.dto.MallOrderRefundDTO;
import com.sc.nft.dto.SupplierManageBindingSpecsGetSupplyNameDTO;
import com.sc.nft.entity.ApiOrderDirect;
import com.sc.nft.entity.ExpenditureRecord;
import com.sc.nft.entity.MallActivity;
import com.sc.nft.entity.MallActivityExchange;
import com.sc.nft.entity.MallActivityShare;
import com.sc.nft.entity.MallActivityShareSpecs;
import com.sc.nft.entity.MallActivitySpecs;
import com.sc.nft.entity.MallDeliveryAddress;
import com.sc.nft.entity.MallMemberEquityUseRecord;
import com.sc.nft.entity.MallOrder;
import com.sc.nft.entity.MallOrderExchange;
import com.sc.nft.entity.MallOrderIncome;
import com.sc.nft.entity.MallOrderProduct;
import com.sc.nft.entity.MallOrderRefund;
import com.sc.nft.entity.MallOrderRefundStatusLog;
import com.sc.nft.entity.MallOrderStatusLog;
import com.sc.nft.entity.MallOrderUpdateAddressLog;
import com.sc.nft.entity.MallPayOrderRecord;
import com.sc.nft.entity.MallProduct;
import com.sc.nft.entity.MallProductSpecs;
import com.sc.nft.entity.MallProfitTemplate;
import com.sc.nft.entity.MallUserActivitySummary;
import com.sc.nft.entity.RefundRecordVO;
import com.sc.nft.entity.UserAssets;
import com.sc.nft.entity.UserCollection;
import com.sc.nft.entity.UserCoupons;
import com.sc.nft.entity.UserCreatorInfo;
import com.sc.nft.entity.UserEquityProps;
import com.sc.nft.entity.UserInfo;
import com.sc.nft.entity.UserWallet;
import com.sc.nft.entity.UserWalletDetail;
import com.sc.nft.entity.dto.ApiOrderDirectDTO;
import com.sc.nft.entity.dto.BatchDeliverDTO;
import com.sc.nft.entity.dto.BuyLimitDTO;
import com.sc.nft.entity.dto.MallMemberCheckHasPreemptionDTO;
import com.sc.nft.entity.dto.SaasTaskBurialPointDTO;
import com.sc.nft.entity.dto.UseUserCouponsDTO;
import com.sc.nft.entity.vo.DistributionOrderVO;
import com.sc.nft.entity.vo.ExportOrderListVO;
import com.sc.nft.entity.vo.UseCouponsCommand;
import com.sc.nft.entity.vo.mall.AdminMallOrderProductDetailsVO;
import com.sc.nft.entity.vo.mall.AdminMallPageOrderVO;
import com.sc.nft.entity.vo.mall.AdminOrderDetailsVO;
import com.sc.nft.entity.vo.mall.AdminPageRefundOrderVO;
import com.sc.nft.entity.vo.mall.AdminRefundDetailsVO;
import com.sc.nft.entity.vo.mall.AdminRefundProductDetails;
import com.sc.nft.entity.vo.mall.CreateMallOrderVO;
import com.sc.nft.entity.vo.mall.MallOrderConfirmProductVO;
import com.sc.nft.entity.vo.mall.MallOrderDeliveryAddressVO;
import com.sc.nft.entity.vo.mall.MallOrderDetailsExchangeVO;
import com.sc.nft.entity.vo.mall.MallOrderDetailsVO;
import com.sc.nft.entity.vo.mall.MallOrderProductDetailsVO;
import com.sc.nft.entity.vo.mall.MallOrderStatusVO;
import com.sc.nft.entity.vo.mall.OrderConfirmByOrderNoVO;
import com.sc.nft.entity.vo.mall.OrderConfirmVO;
import com.sc.nft.entity.vo.mall.OrderExchangeVO;
import com.sc.nft.entity.vo.mall.PageMallOrderVO;
import com.sc.nft.entity.vo.mall.PageMallPopularizeOrderVO;
import com.sc.nft.entity.vo.mall.ProductValuationVO;
import com.sc.nft.entity.vo.mall.RefundDetailsVO;
import com.sc.nft.entity.vo.mall.RefundInfoVO;
import com.sc.nft.entity.vo.mall.RefundValuationVO;
import com.sc.nft.entity.vo.mall.UpdateMallDeliveryAddressVO;
import com.sc.nft.enums.ApprovalStatusEnum;
import com.sc.nft.enums.AssetChangeLogEnum;
import com.sc.nft.enums.CoinCategoryEnum;
import com.sc.nft.enums.CouponsTypeEnum;
import com.sc.nft.enums.ExpenditureRecordTypeEnum;
import com.sc.nft.enums.LinkTypeEnums;
import com.sc.nft.enums.MallBuyLimitTypeEnum;
import com.sc.nft.enums.MallChannelEnum;
import com.sc.nft.enums.MallExchangeEnum;
import com.sc.nft.enums.MallOrderIncomeTypeEnum;
import com.sc.nft.enums.MallOrderPushTypeEnum;
import com.sc.nft.enums.MallOrderRefundStatusEnum;
import com.sc.nft.enums.MallOrderRefundTypeEnum;
import com.sc.nft.enums.MallOrderStatusEnum;
import com.sc.nft.enums.MallRefundStatusEnum;
import com.sc.nft.enums.MessageTopic;
import com.sc.nft.enums.PayMethodEnum;
import com.sc.nft.enums.PayStatusEnum;
import com.sc.nft.enums.PayTypeEnum;
import com.sc.nft.enums.ProductTypeEnum;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.enums.RefundReasonEnum;
import com.sc.nft.enums.SaasTaskMeetConditionsLocationEnum;
import com.sc.nft.enums.SaasTaskTypeEnum;
import com.sc.nft.enums.SourceEnum;
import com.sc.nft.enums.UpdateAddrOperationTypeEnums;
import com.sc.nft.enums.UserBalanceTypeEnum;
import com.sc.nft.enums.UserEquityPropsUseTypeEnum;
import com.sc.nft.enums.WalletDetailTypeEnum;
import com.sc.nft.enums.task.ActivityTaskTypeEnum;
import com.sc.nft.enums.task.ActivityTypeEnum;
import com.sc.nft.enums.task.ParticipantsEnum;
import com.sc.nft.enums.task.TaskOrderTypeEnum;
import com.sc.nft.enums.task.TaskTypeEnum;
import com.sc.nft.exception.GlobalException;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.feign.WxMiniUserPointsClient;
import com.sc.nft.helper.HfPayHelper;
import com.sc.nft.helper.LlPayHelper;
import com.sc.nft.helper.MessageQueueHelper;
import com.sc.nft.helper.SmartSupplyHelper;
import com.sc.nft.req.points.PointsReq;
import com.sc.nft.service.ActivityTaskService;
import com.sc.nft.service.ApiOrderDirectService;
import com.sc.nft.service.DaoChainInfoService;
import com.sc.nft.service.MallActivityExchangeService;
import com.sc.nft.service.MallActivityService;
import com.sc.nft.service.MallActivityShareService;
import com.sc.nft.service.MallActivityShareSpecsService;
import com.sc.nft.service.MallActivitySpecsService;
import com.sc.nft.service.MallDeliveryAddressService;
import com.sc.nft.service.MallMemberEquityService;
import com.sc.nft.service.MallMemberEquityUseRecordService;
import com.sc.nft.service.MallOrderProductService;
import com.sc.nft.service.MallOrderPushService;
import com.sc.nft.service.MallOrderRefundService;
import com.sc.nft.service.MallOrderRefundStatusLogService;
import com.sc.nft.service.MallOrderService;
import com.sc.nft.service.MallOrderStatusLogService;
import com.sc.nft.service.MallPayOrderRecordService;
import com.sc.nft.service.MallProductService;
import com.sc.nft.service.MallProductSpecsService;
import com.sc.nft.service.MallProfitTemplateService;
import com.sc.nft.service.MallUserActivityRankingDetailService;
import com.sc.nft.service.MallUserActivitySummaryService;
import com.sc.nft.service.MallUserPropsRewardsDetailService;
import com.sc.nft.service.TaskService;
import com.sc.nft.service.UserAssetsService;
import com.sc.nft.service.UserCollectionService;
import com.sc.nft.service.UserCouponsService;
import com.sc.nft.service.UserCreatorInfoService;
import com.sc.nft.service.UserEquityPropsService;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.Result;
import com.sc.nft.util.BigDecimalUtils;
import com.sc.nft.util.OrderNoUtil;
import jodd.typeconverter.Convert;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * ip商城订单主表服务接口实现
 *
 * @author Sun
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2023-05-09 10:46:38
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MallOrderServiceImpl implements MallOrderService {
    private final MallOrderDao mallOrderDao;
    private final MallOrderProductService mallOrderProductService;
    private final MallOrderStatusLogService mallOrderStatusLogService;
    private final MallActivityService mallActivityService;
    private final MallActivitySpecsService mallActivitySpecsService;
    private final MallActivityExchangeService mallActivityExchangeService;
    private final MallProductService mallProductService;
    private final MallProductSpecsService mallProductSpecsService;
    private final UserCollectionService userCollectionService;
    private final UserAssetsService userAssetsService;
    private final UserAssetsDao userAssetsDao;
    private final UserEquityPropsService userEquityPropsService;
    private final MallDeliveryAddressService mallDeliveryAddressService;
    private final UserCreatorInfoService userCreatorInfoService;
    private final MallOrderExchangeDao mallOrderExchangeDao;
    private final MallOrderIncomeDao mallOrderIncomeDao;
    private final StaticDataDao staticDataDao;
    private final DaoChainInfoService daoChainInfoService;
    private final SmartSupplyHelper smartSupplyHelper;
    private final HfPayHelper hfPayHelper;
    private final LlPayHelper llPayHelper;
    private final UserInfoDao userInfoDao;
    private final MallPayOrderRecordService mallPayOrderRecordService;
    private final UserWalletDao userWalletDao;
    private final UserWalletDetailDao userWalletDetailDao;
    private final ExpenditureRecordDao expenditureRecordDao;
    private final MallOrderStatusLogDao mallOrderStatusLogDao;
    private final ActivityTaskService activityTaskService;
    private final TaskService taskService;
    private final ApiOrderDirectService apiOrderDirectService;
    private final MallOrderRefundStatusLogService mallOrderRefundStatusLogService;
    private final UserCouponsService userCouponsService;
    @Autowired
    MallOrderRefundService mallOrderRefundService;
    private final MallActivityShareService mallActivityShareService;
    private final MallActivityShareSpecsService mallActivityShareSpecsService;
    private final MessageQueueHelper messageQueueHelper;
    private final MallProfitTemplateService mallProfitTemplateService;
    private final MallMemberEquityUseRecordService mallMemberEquityUseRecordService;
    private final MallMemberEquityTargetDao mallMemberEquityTargetDao;
    private final MallMemberEquityService mallMemberEquityService;
    private final WxMiniUserPointsClient wxMiniUserPointsClient;
    private final MallOrderUpdateAddressLogDao mallOrderUpdateAddressLogDao;
    private final MallOrderPushService mallOrderPushService;
    private final Redisson redisson;
    private final SupplierManageBindingDao supplierManageBindingDao;
    private final MallOrderBillDao mallOrderBillDao;
    private final MallUserActivitySummaryService mallUserActivitySummaryService;
    private final MallUserActivityRankingDetailService mallUserActivityRankingDetailService;
    private final MallUserPropsRewardsDetailService mallUserPropsRewardsDetailService;
    private static String TARGETTIMESTRING = "2024-09-29 00:00:00";


    @Override
    public ProductValuationVO productValuation(Long activityId, Long specsId, Integer count, UserInfo user, Long shareTeamId) {
        //获取活动信息
        MallActivity mallActivity = mallActivityService.getByIdAndApprovalStatus(activityId, ApprovalStatusEnum.PASS);
        //营销活动是否存在
        Assert.notNull(mallActivity, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_DOES_NOT_EXIST));
        Assert.isTrue(mallActivity.getActivityType() == ActivityTypeEnum.SALES, () -> new GlobalRunTimeException(ErrorCode.MALL_WRONG_PRODUCT_TYPE));

        MallActivitySpecs mallActivitySpecs = mallActivitySpecsService.getById(specsId);
        //营销活动规格是否存在
        Assert.notNull(mallActivitySpecs, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_SPECIFICATION_DOES_NOT_EXIST));

        //校验参与对象
        if (mallActivity.getParticipants() == ParticipantsEnum.APPOINT) {//如果是指定NFT
            Long collectionId = mallActivity.getCollectionId();
            //判断id是否为空
            Assert.notNull(collectionId, () -> new GlobalRunTimeException(ErrorCode.COLLECTION_NOT_FOUND));
            //判断id是否为0
            Assert.isFalse(collectionId == 0L, () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_IS_NO_LONGER_AVAILABLE));
            //不满足兑换条件
            Assert.isTrue(userCollectionService.getIsContainsAndIsHoldAndIsOpenAndOnConsignByCollectionId(collectionId, user.getId()) > 0, () -> new GlobalRunTimeException(ErrorCode.DOES_NOT_MEET_THE_REDEMPTION_CONDITIONS));
        }

        //校验购买上限
        Integer userBuyCount = mallOrderProductService.getUserBuyCountByUserIdAndActivityId(user.getId(), mallActivity.getId());
        MallUserActivitySummary mallUserActivitySummary = mallUserActivitySummaryService.get(user.getId());
        BuyLimitDTO buyLimitDTO = mallActivityService.convertBuyLimit(mallActivity, mallUserActivitySummary);
        Assert.isTrue(userBuyCount + count <= buyLimitDTO.getBuyLimit(), () -> new GlobalRunTimeException(ErrorCode.MALL_THE_CURRENT_PURCHASE_QUANTITY_HAS_REACHED_THE_UPPER_LIMIT));

        // 分享购拼团
        MallActivityShare mallActivityShare = null;
        if (Objects.nonNull(shareTeamId)) {
            mallActivityShare = mallActivityShareService.getByTeamId(shareTeamId);
            if (!mallActivityShare.getStatus()) {
                throw new GlobalRunTimeException("活动已结束");
            }
        }

        if (Objects.nonNull(mallActivityShare)) {
            MallActivityShareSpecs mallActivityShareSpecs = mallActivityShareSpecsService.getMallActivityShareSpecs(mallActivityShare.getId(), mallActivityShare.getActivityId(), mallActivitySpecs.getId());
            if (Objects.isNull(mallActivityShareSpecs)) {
                throw new GlobalRunTimeException("活动已结束");
            }
            mallActivitySpecs.setSalesPrice(mallActivityShareSpecs.getSalesPrice());
        }

        //售价
        BigDecimal salesPrice = mallActivitySpecs.getSalesPrice();
        //售价 * 数量 = 总价
        BigDecimal totalPrice = salesPrice.multiply(Convert.toBigDecimal(count)).setScale(2, BigDecimal.ROUND_DOWN);

        ProductValuationVO productValuationVO = new ProductValuationVO();
        productValuationVO.setTotalPrice(totalPrice);
        productValuationVO.setMaxCount(buyLimitDTO.getBuyLimit() - userBuyCount > 0 ? buyLimitDTO.getBuyLimit() - userBuyCount : 0);
        return productValuationVO;
    }

    public static List<MallActivityExchange> exchangeDistinctOld(List<MallActivityExchange> dataList) {
        if(dataList == null){
            return new ArrayList<>();
        }
        // 去重逻辑：type=3 按 linkId 去重；type=1 和 type=2 按 type 去重
        Map<MallExchangeEnum, MallActivityExchange> typeMap = new HashMap<>();
        Map<Long, MallActivityExchange> linkIdMap = new HashMap<>();

        // 用于存储groupId为0的记录
        List<MallActivityExchange> zeroGroupIdList = new ArrayList<>();

        for (MallActivityExchange data : dataList) {
            // 收集groupId为0的记录
            if (data.getGroupId() == 0) {
                zeroGroupIdList.add(data);
            }
        }

        // 如果有groupId为0的记录，优先返回这些记录
        if (!zeroGroupIdList.isEmpty()) {
            return zeroGroupIdList;
        }

        // 如果没有groupId为0的记录，返回groupId最小的一组
        long minGroupId = dataList.stream()
                .mapToLong(MallActivityExchange::getGroupId)
                .filter(groupId -> groupId > 0) // 过滤掉groupId为0的记录
                .min()
                .orElse(Long.MAX_VALUE); // 如果没有有效的groupId，返回最大值

        // 过滤出groupId最小的记录
        List<MallActivityExchange> minGroupIdList = dataList.stream()
                .filter(data -> data.getGroupId() == minGroupId)
                .collect(Collectors.toList());

        for (MallActivityExchange data : minGroupIdList) {
            if (data.getType() == MallExchangeEnum.EQUITY) {
                linkIdMap.putIfAbsent(data.getLinkId(), data);
            } else {
                typeMap.putIfAbsent(data.getType(), data);
            }
        }

        // 合并去重结果
        List<MallActivityExchange> result = new ArrayList<>(linkIdMap.values());
        result.addAll(typeMap.values());
        return result;
    }


    @Override
    public OrderConfirmVO orderConfirm(Long activityId, Long specsId, Integer count, UserInfo user, Long shareTeamId,Long groupId) {
        //获取活动信息
        MallActivity mallActivity = mallActivityService.getByIdAndApprovalStatus(activityId, ApprovalStatusEnum.PASS);
        //营销活动是否存在
        Assert.notNull(mallActivity, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_DOES_NOT_EXIST));

        //是否存在待付款的订单
        List<MallOrder> orderList = mallOrderDao.getListByUserIdAndStatus(user.getId(), MallOrderStatusEnum.WAIT_PAY);
        if (orderList.size() > 0) {
            Assert.isFalse(mallActivity.getActivityType() == ActivityTypeEnum.SALES, () -> new GlobalRunTimeException(ErrorCode.WAIT_PAY_ORDER));
        }

        MallActivitySpecs mallActivitySpecs = mallActivitySpecsService.getById(specsId);
        //营销活动规格是否存在
        Assert.notNull(mallActivitySpecs, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_SPECIFICATION_DOES_NOT_EXIST));


        MallProduct mallProduct = mallProductService.getById(mallActivity.getProductId());
        //商品信息
        Assert.notNull(mallProduct, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_DOES_NOT_EXIST));

        MallProductSpecs mallProductSpecs = mallProductSpecsService.getById(mallActivitySpecs.getSpecsId());
        //商品规格
        Assert.notNull(mallProductSpecs, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_SPECIFICATION_DOES_NOT_EXIST));

        Assert.isTrue(mallActivity.getStatus(), () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_IS_NO_LONGER_AVAILABLE));
        //判断是否为优先购状态下,校验开始时间
        DateTime now = DateTime.now();
        if (now.isBefore(mallActivity.getStartTime())) {
            MallMemberCheckHasPreemptionDTO checkHasPreemptionDTO = mallMemberEquityService.checkHasPreemption(user, specsId);
            Assert.notNull(checkHasPreemptionDTO, () -> new GlobalRunTimeException(ErrorCode.NOT_BEGIN));
            DateTime checkTime = DateUtil.offsetMinute(mallActivity.getStartTime(), -checkHasPreemptionDTO.getPrioritizeTheLeadTime());
            if (!DateUtil.isIn(now, checkTime, mallActivity.getStartTime())) {
                throw new GlobalRunTimeException(ErrorCode.NOT_BEGIN);
            }
        } else {
            Assert.isTrue(now.isAfter(mallActivity.getStartTime()), () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_IS_NO_LONGER_AVAILABLE));
        }
        if (Objects.nonNull(mallActivity.getEndTime())) {
            Assert.isTrue(now.isBefore(mallActivity.getEndTime()), () -> new GlobalRunTimeException(ErrorCode.ACTIVITY_HAS_ENDED));
        }
        //数量不足  1.限购数量达到上限 2.库存不足
        Assert.isTrue(mallActivitySpecs.getUsableStockCount() - count >= 0, () -> new GlobalRunTimeException(ErrorCode.MALL_THE_CURRENT_PURCHASE_QUANTITY_HAS_REACHED_THE_UPPER_LIMIT));
//        Integer userBuyCount = mallOrderProductService.getUserBuyCountByUserIdAndActivityId(user.getId(), mallActivity.getId());
        //库存充足的情况下，还要判断用户本次购买有没有达到上限
//        Assert.isTrue(userBuyCount - count > 0,() -> new GlobalRunTimeException(ErrorCode.MALL_THE_CURRENT_PURCHASE_QUANTITY_HAS_REACHED_THE_UPPER_LIMIT));

        OrderConfirmVO orderConfirmVO = new OrderConfirmVO();
        //购买类型校验(积分兑换)
        if (mallActivity.getActivityType() == ActivityTypeEnum.EXCHANGE) {  //品牌直销 现金
            //活动需要的单位积分、虚拟道具、NFT消耗数量
            List<MallActivityExchange> activityExchangeList;
            if(groupId == null){
                activityExchangeList = exchangeDistinctOld(mallActivityExchangeService.getListByActivityIdAndSpecsidOld(mallActivity.getId(), mallActivitySpecs.getId()));
            }else{
                activityExchangeList = mallActivityExchangeService.getListByActivityIdAndSpecsid(mallActivity.getId(), mallActivitySpecs.getId(), groupId);
            }
            //商品配置是否存在
            Assert.isFalse(activityExchangeList.size() == 0, () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_CONFIGURATION_IS_WRONG));

            //积分单位的消耗数量
            int totalCostNum = activityExchangeList.stream().filter(activity -> activity.getType() == MallExchangeEnum.INTEGRAL).mapToInt(MallActivityExchange::getCostNum).sum();
            UserAssets userAssets = userAssetsDao.getByUserIdAndCoinId(user.getId(), CoinCategoryEnum.INTEGRAL.getCode());

            BigDecimal tokenNum = (userAssets != null) ? userAssets.getTokenNum() : BigDecimal.ZERO;

            //积分不足
            Assert.isTrue(tokenNum.compareTo(Convert.toBigDecimal(totalCostNum * count)) > -1, () -> new GlobalRunTimeException(ErrorCode.INTEGRAL_NOT_ENOUGH));//不满足兑换条件
            //积分消耗
            //校验权益道具
            List<MallActivityExchange> equityList = activityExchangeList.stream().filter(o -> o.getType() == MallExchangeEnum.EQUITY).collect(Collectors.toList());
            //虚拟道具、NFT 单位的消耗数量
            Map<String, Integer> equityCostNumMap = activityExchangeList.stream().filter(o -> o.getType() == MallExchangeEnum.EQUITY)
                    .collect(Collectors.toMap(
                            exchange -> String.format("%d_%d", exchange.getActivitySpecsId(), exchange.getLinkId()),
                            MallActivityExchange::getCostNum,
                            (id1, id2) -> id1
                    ));

            int nftCostNum = activityExchangeList.stream().filter(activity -> activity.getType() == MallExchangeEnum.NFT).mapToInt(MallActivityExchange::getCostNum).sum();
            for (MallActivityExchange mallActivityExchange : equityList) {
                //单位商品的道具消耗数量
                Integer costNum = mallActivityExchange.getCostNum() * count;
                Long linkId = mallActivityExchange.getLinkId();
                Assert.isTrue(userEquityPropsService.getHavingListByUserIdAndEquityPropsIdAndLimit(user.getId(), linkId, costNum).size() >= costNum, () -> new GlobalRunTimeException(ErrorCode.EQUITY_PROPS_NOT_ENOUGH));
            }

            //校验NFT
            List<MallActivityExchange> nftList = activityExchangeList.stream().filter(o -> o.getType() == MallExchangeEnum.NFT).collect(Collectors.toList());
            for (MallActivityExchange mallActivityExchange : nftList) {
                Integer costNum = mallActivityExchange.getCostNum() * count;
                Long linkId = mallActivityExchange.getLinkId();
                Assert.isTrue(userCollectionService.getIsContainsAndIsHoldAndIsOpenAndOnConsignByCollectionId(linkId, user.getId()) >= costNum, () -> new GlobalRunTimeException(ErrorCode.MALL_DOES_NOT_MEET_THE_REDEMPTION_CONDITIONS));
            }
            //获取积分、 虚拟道具、NFT道具消耗的单位数量 然后分别 * count
            activityExchangeList.forEach(mallActivityExchange -> {
                if (mallActivityExchange.getType() == MallExchangeEnum.INTEGRAL) {
                    mallActivityExchange.setCostNum(totalCostNum * count);
                }
                if (mallActivityExchange.getType() == MallExchangeEnum.EQUITY) {
                    Integer equityCostNum = equityCostNumMap.get(mallActivityExchange.getActivitySpecsId() + "_" + mallActivityExchange.getLinkId());
                    mallActivityExchange.setCostNum((equityCostNum == null ? 0 : equityCostNum) * count);
                }
                if (mallActivityExchange.getType() == MallExchangeEnum.NFT) {
                    mallActivityExchange.setCostNum(nftCostNum * count);
                }
            });
            orderConfirmVO.setExchangelist(activityExchangeList);
        }

        // 分享购拼团
        MallActivityShare mallActivityShare = null;
        if (Objects.nonNull(shareTeamId)) {
            mallActivityShare = mallActivityShareService.getByTeamId(shareTeamId);
            if (!mallActivityShare.getStatus()) {
                throw new GlobalRunTimeException("活动已结束");
            }
        }

        if (Objects.nonNull(mallActivityShare)) {
            MallActivityShareSpecs mallActivityShareSpecs = mallActivityShareSpecsService.getMallActivityShareSpecs(mallActivityShare.getId(), mallActivityShare.getActivityId(), mallActivitySpecs.getId());
            if (Objects.isNull(mallActivityShareSpecs)) {
                throw new GlobalRunTimeException("活动已结束");
            }
            mallActivitySpecs.setSalesPrice(mallActivityShareSpecs.getSalesPrice());
        }

        //售价
        BigDecimal salesPrice = mallActivitySpecs.getSalesPrice();

        //售价 * 数量 = 总价
        BigDecimal totalPrice = salesPrice.multiply(Convert.toBigDecimal(count)).setScale(2, BigDecimal.ROUND_DOWN);

        orderConfirmVO.setProductSalesPrice(salesPrice);
        orderConfirmVO.setTotalPrice(totalPrice);
        orderConfirmVO.setPayPostage(BigDecimal.ZERO);
        orderConfirmVO.setPayPrice(totalPrice);
        orderConfirmVO.setTotalNum(count);
        orderConfirmVO.setActivityType(mallActivity.getActivityType());
        if (CollUtil.isEmpty(orderConfirmVO.getExchangelist())) {
            //活动需要的单位积分、虚拟道具、NFT消耗数量
            List<MallActivityExchange> activityExchangeList;
            if(groupId == null){
                activityExchangeList = exchangeDistinctOld(mallActivityExchangeService.getListByActivityIdAndSpecsidOld(mallActivity.getId(), mallActivitySpecs.getId()));
            }else{
                activityExchangeList = mallActivityExchangeService.getListByActivityIdAndSpecsid(mallActivity.getId(), mallActivitySpecs.getId(), groupId);
            }
            orderConfirmVO.setExchangelist(activityExchangeList);
        }
        orderConfirmVO.setActivityId(mallActivity.getId());
        orderConfirmVO.setSpecsId(mallActivitySpecs.getId());

        List<MallOrderConfirmProductVO> productList = Lists.newArrayList();
        MallOrderConfirmProductVO mallOrderConfirmProductVO = new MallOrderConfirmProductVO();
        mallOrderConfirmProductVO.setThumbnail(mallProduct.getThumbnail());
        mallOrderConfirmProductVO.setProductName(mallProduct.getProductName());
        mallOrderConfirmProductVO.setProductSpecsName(mallProductSpecs.getSpecsName());

        productList.add(mallOrderConfirmProductVO);
        orderConfirmVO.setProductList(productList);

        return orderConfirmVO;
    }

    @Override
    public OrderConfirmByOrderNoVO orderConfirmByOrderId(String orderNo) {
        MallOrder mallOrder = mallOrderDao.getByOrderNo(orderNo);
        Assert.notNull(mallOrder, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        Assert.isTrue(mallOrder.getStatus() == MallOrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_STATUS_ERROR));

        Long orderId = mallOrder.getId();
        List<MallOrderProduct> orderProductList = mallOrderProductService.getListByOrderId(orderId);
        Assert.isTrue(orderProductList.size() > 0, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        MallOrderProduct mallOrderProduct = orderProductList.get(0);

        OrderConfirmByOrderNoVO orderConfirmVO = BeanUtil.copyProperties(mallOrder, OrderConfirmByOrderNoVO.class);
        orderConfirmVO.setProductSalesPrice(mallOrderProduct.getProductSalesPrice());
        orderConfirmVO.setPayPostage(mallOrder.getPayPostage());
        orderConfirmVO.setPayPrice(mallOrder.getRealPrice());
        orderConfirmVO.setCouponAmount(mallOrder.getCouponAmount());
        orderConfirmVO.setTotalPrice(mallOrder.getTotalPrice());
        orderConfirmVO.setSpecsId(mallOrderProduct.getActivitySpecsId());
        orderConfirmVO.setActivityId(mallOrderProduct.getActivityId());

        List<MallOrderConfirmProductVO> voList = orderProductList.stream()
                .map(activityExchange -> {
                    return BeanUtil.copyProperties(activityExchange, MallOrderConfirmProductVO.class);
                })
                .collect(Collectors.toList());
        orderConfirmVO.setProductList(voList);

        orderConfirmVO.setExchangelist(mallActivityExchangeService.getListByActivityIdAndSpecsid(mallOrderProduct.getActivityId(), mallOrderProduct.getActivitySpecsId(),null));

        MallOrderDeliveryAddressVO mallOrderDeliveryAddressVO = new MallOrderDeliveryAddressVO();
        mallOrderDeliveryAddressVO.setRecipientName(mallOrder.getUserRealName());
        mallOrderDeliveryAddressVO.setContactNumber(mallOrder.getUserTel());
        mallOrderDeliveryAddressVO.setState(mallOrder.getProvince());
        mallOrderDeliveryAddressVO.setCity(mallOrder.getCity());
        mallOrderDeliveryAddressVO.setArea(mallOrder.getArea());
        mallOrderDeliveryAddressVO.setDetailedAddress(mallOrder.getUserAddress());
        orderConfirmVO.setMallDeliveryAddress(mallOrderDeliveryAddressVO);
        if (mallOrder.getIsVirtual()) {
            ApiOrderDirect apiOrderDirect = apiOrderDirectService.getByOrderId(mallOrder.getId());
            if (Objects.nonNull(apiOrderDirect)) {
                orderConfirmVO.setApiOrderDirectDTO(ApiOrderDirectDTO.build(apiOrderDirect));
            }
        }
        return orderConfirmVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CreateMallOrderVO createMallOrder(Long activityId, Long specsId, Integer count, UserInfo user, Long mallDeliveryAddressId, String dealPwd, String apiChargeAccount, Long userCouponsId, Long shareTeamId,Long groupId) {
        // 分享购拼团
        MallActivityShare mallActivityShare = null;
        if (Objects.nonNull(shareTeamId)) {
            mallActivityShare = mallActivityShareService.getByTeamId(shareTeamId);
            if (!mallActivityShare.getStatus()) {
                throw new GlobalRunTimeException("活动已结束");
            }
        }
        //1.校验商品
        //获取活动信息
        MallActivity mallActivity = mallActivityService.getByIdAndApprovalStatus(activityId, ApprovalStatusEnum.PASS);
        MallActivitySpecs mallActivitySpecs = mallActivitySpecsService.getById(specsId);
        MallProduct mallProduct = mallProductService.getById(mallActivity.getProductId());
        MallProductSpecs mallProductSpecs = mallProductSpecsService.getById(mallActivitySpecs.getSpecsId());

        MallDeliveryAddress mallDeliveryAddress = mallDeliveryAddressService.getAddressByUserIdAndId(user.getId(), mallDeliveryAddressId);
        //优先购判断实体类
        CheckProductHasPreemptionDTO hasPreemptionDTO = new CheckProductHasPreemptionDTO();
        //校验商品
        checkMallProduct(mallActivity, mallActivitySpecs, mallProduct, mallProductSpecs, mallDeliveryAddress, count, user, hasPreemptionDTO);

        MallOrder mallOrder = new MallOrder();
        mallOrder.setUserId(user.getId());
        mallOrder.setOrderNo(OrderNoUtil.getOrderNo());
        mallOrder.setStatus(MallOrderStatusEnum.WAIT_PAY);
        mallOrder.setRefundStatus(MallOrderRefundStatusEnum.NEW_NOT_APPLY);
        mallOrder.setIsAllowedShoppingCoupons(mallProduct.isAllowedShoppingCoupons());

        // 判断是否为虚拟商品订单
        mallOrder.setIsVirtual(false);
        if (ProductTypeEnum.VIRTUAL == mallProduct.getType()) {
            if (StringUtils.isBlank(apiChargeAccount)) {
                throw new GlobalRunTimeException(ErrorCode.FILL_IN_THE_TOP_UP_ACCOUNT);
            }
            mallOrder.setIsVirtual(true);
            mallOrder.setUserRealName("");
            mallOrder.setUserTel("");
            mallOrder.setProvince("");
            mallOrder.setCity("");
            mallOrder.setArea("");
            mallOrder.setUserAddress("");
        } else {
            //2.查询地址
            mallOrder.setUserRealName(mallDeliveryAddress.getRecipientName());
            mallOrder.setUserTel(mallDeliveryAddress.getContactNumber());
            mallOrder.setProvince(mallDeliveryAddress.getState());
            mallOrder.setCity(mallDeliveryAddress.getCity());
            mallOrder.setArea(mallDeliveryAddress.getArea());
            mallOrder.setUserAddress(mallDeliveryAddress.getDetailedAddress());
        }

        //3.获取商品信息
        //售价
        BigDecimal salesPrice = BigDecimal.ZERO;
        if (Objects.nonNull(mallActivityShare)) {
            mallOrder.setShareTeamId(shareTeamId);
            MallActivityShareSpecs mallActivityShareSpecs = mallActivityShareSpecsService.getMallActivityShareSpecs(mallActivityShare.getId(), mallActivityShare.getActivityId(), specsId);
            salesPrice = mallActivityShareSpecs.getSalesPrice();
        } else {
            salesPrice = mallActivitySpecs.getSalesPrice();
        }
        //成本价
        BigDecimal costPrice = mallActivitySpecs.getCostPrice();
        // 活动成本
        BigDecimal activityCostPrice = mallActivitySpecs.getActivityCostPrice();
        // 拖低价
        BigDecimal reservePrice = mallActivitySpecs.getReservePrice();

        //售价 * 数量 = 总价
        BigDecimal totalPrice = salesPrice.multiply(Convert.toBigDecimal(count)).setScale(2, BigDecimal.ROUND_DOWN);
        mallOrder.setTotalPrice(totalPrice);//商品总价
        mallOrder.setRealPrice(totalPrice);//实际需要支付的价格
        mallOrder.setTotalNum(count);
        mallOrder.setPayPostage(BigDecimal.ZERO);
        mallOrder.setPayPrice(totalPrice);
        //类型  品牌销售 活动兑换
        mallOrder.setActivityType(mallActivity.getActivityType());
        mallOrder.setDaoId(mallProduct.getDaoId());
        mallOrder.setDaoName(userCreatorInfoService.getById(mallProduct.getDaoId()).getDaoName());
        //订单有效期
        mallOrder.setExpiredTime(DateUtil.offsetMinute(DateTime.now(), 30));
        if (mallProduct.getProductChannel() == MallChannelEnum.SMART) {
            JSONObject result = smartSupplyHelper.createOrder(mallProduct, mallProductSpecs, mallOrder);
            try {
                JSONObject data = result.getJSONObject("data");
                JSONObject resultObject = data.getJSONArray("orderDetailList").getJSONObject(0);
                mallOrder.setSupplyOrderNo(data.getString("result"));
                mallOrder.setApiOrderNo(resultObject.getString("apiOrderSn"));
                mallOrder.setSupplyOrderId(resultObject.getLong("id"));
            } catch (Exception e) {
                log.error("智慧供应链返回结构解析失败,result:{}", result, e);
            }
        }
        mallOrder.insert();
        if (Objects.nonNull(userCouponsId)) {
            // 使用优惠券实体类
            UseCouponsCommand useCouponsCommand = new UseCouponsCommand();
            useCouponsCommand.setOrderId(mallOrder.getId());
            useCouponsCommand.setOrderNo(mallOrder.getOrderNo());
            useCouponsCommand.setMoney(mallOrder.getRealPrice());
            useCouponsCommand.setActivityProductId(activityId);
            UseUserCouponsDTO useUserCouponsDTO = userCouponsService.useUserCoupons(userCouponsId, useCouponsCommand, user.getId());
            if (useUserCouponsDTO.getCanUse()) {
                BigDecimal realPrice = mallOrder.getRealPrice();
                BigDecimal money = BigDecimal.ZERO;
                BigDecimal newRealPrice = BigDecimal.ZERO;
                if (useUserCouponsDTO.getCouponsType().getType().equals(CouponsTypeEnum.DISCOUNT_COUPON.getType())) {
                    // 根据是满减券算出实际支付的价格
                    money = useUserCouponsDTO.getMoney();
                    newRealPrice = realPrice.subtract(money);
                } else if (useUserCouponsDTO.getCouponsType().getType().equals(CouponsTypeEnum.DISCOUNT_PROPORTION_COUPON.getType())) {
                    // 根据是折扣券算出实际支付的价格
                    money = realPrice;
                    if (BigDecimalUtils.greaterZero(useUserCouponsDTO.getProportion())) {
                        //折扣是0
                        newRealPrice = realPrice.multiply(BigDecimalUtils.divide(useUserCouponsDTO.getProportion(), BigDecimal.TEN)).setScale(2, RoundingMode.DOWN);
                        money = realPrice.subtract(newRealPrice);
                    }
                }
                mallOrder.setCouponAmount(money);
                mallOrder.setRealPrice(newRealPrice);
                mallOrder.setPayPrice(newRealPrice);
                mallOrder.updateById();
            } else {
                log.info("使用优惠券失败,失败异常:{}", useUserCouponsDTO.getCanNotUseReason());
            }
        }

        if (mallOrder.getIsVirtual()) {
            // 虚拟商品订单
            apiOrderDirectService.create(mallOrder.getId(), mallOrder.getOrderNo(), mallProductSpecs.getApiProductId(), apiChargeAccount, count);
        }

        //订单关联商品表
        MallOrderProduct mallOrderProduct = new MallOrderProduct();
        mallOrderProduct.setActivityType(mallActivity.getActivityType());
        mallOrderProduct.setMallOrderId(mallOrder.getId());
        mallOrderProduct.setProductId(mallActivity.getProductId());
        mallOrderProduct.setActivityId(mallActivity.getId());
        mallOrderProduct.setActivitySpecsId(specsId);
        mallOrderProduct.setProductSalesPrice(salesPrice);
        mallOrderProduct.setProductCostPrice(costPrice);
        mallOrderProduct.setActivityCostPrice(activityCostPrice);
        mallOrderProduct.setReservePrice(reservePrice);
        mallOrderProduct.setProductNum(count);
        mallOrderProduct.setThumbnail(mallProduct.getThumbnail());
        mallOrderProduct.setProductName(mallProduct.getProductName());
        mallOrderProduct.setProductSpecsName(mallProductSpecs.getSpecsName());

        mallOrderProduct.insert();

        //扣减库存
        Assert.isTrue(mallActivitySpecsService.frozenStockByIdAndCount(mallActivitySpecs.getId(), count), () -> new GlobalRunTimeException(ErrorCode.THE_SYSTEM_IS_BUSY_PLEASE_TRY_AGAIN_LATER));
        if (hasPreemptionDTO.getIsHasPreemption() && hasPreemptionDTO.getMallMemberEquityId() != 0) {
            //扣减优先抢可用数量
            Assert.isTrue(mallMemberEquityTargetDao.reduceCanUseNum(hasPreemptionDTO.getMallMemberEquityId(), count), () -> new GlobalRunTimeException(ErrorCode.NOT_ENOUGH_EQUITY_AVAILABLE));
            //会员权益使用记录
            Assert.isTrue(mallMemberEquityUseRecordService.create(hasPreemptionDTO.getMallMemberEquityId(), user.getId(), mallOrder.getId()), () -> new GlobalRunTimeException(ErrorCode.EQUITY_USE_EXCEPTION));
        }
        //日志
        MallOrderStatusLog mallOrderStatusLog = new MallOrderStatusLog();
        mallOrderStatusLog.setMallOrderId(mallOrder.getId());
        mallOrderStatusLog.setChangeType(MallOrderStatusEnum.WAIT_PAY.name());
        mallOrderStatusLog.setChangeMessage(MallOrderStatusEnum.WAIT_PAY.getDescription());
        mallOrderStatusLog.setIsRefund(Boolean.FALSE);
        mallOrderStatusLog.setRemark("下单时间");
        mallOrderStatusLog.insert();


        CreateMallOrderVO createMallOrderVO = BeanUtil.copyProperties(mallOrder, CreateMallOrderVO.class);
        //5.获取支付方式
        //购买类型
        if (mallActivity.getActivityType() == ActivityTypeEnum.EXCHANGE) {  //品牌直销 现金
            //交易密码
            Assert.isTrue(StrUtil.equals(dealPwd, user.getTransactionPassword()), () -> new GlobalRunTimeException(ErrorCode.PASSWORD_ERROR));

            List<MallActivityExchange> activityExchangeList;
            if(groupId == null){
                activityExchangeList = exchangeDistinctOld(mallActivityExchangeService.getListByActivityIdAndSpecsidOld(mallActivity.getId(), mallActivitySpecs.getId()));
            }else{
                activityExchangeList = mallActivityExchangeService.getListByActivityIdAndSpecsid(mallActivity.getId(), mallActivitySpecs.getId(), groupId);
            }
            //商品配置是否存在
            Assert.isFalse(activityExchangeList.size() == 0, () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_CONFIGURATION_IS_WRONG));

            //积分
            int totalCostNum = activityExchangeList.stream()
                    .filter(activity -> activity.getType() == MallExchangeEnum.INTEGRAL)
                    .mapToInt(MallActivityExchange::getCostNum)
                    .sum();

            if (totalCostNum > 0) {
                BigDecimal totalCostNumSum = Convert.toBigDecimal(totalCostNum).multiply(Convert.toBigDecimal(count));
                UserAssets userAssets = userAssetsDao.getByUserIdAndCoinId(user.getId(), CoinCategoryEnum.INTEGRAL.getCode());
                //积分不足
                Assert.isTrue(userAssets.getTokenNum().compareTo(totalCostNumSum) > -1, () -> new GlobalRunTimeException(ErrorCode.INTEGRAL_NOT_ENOUGH));
                //积分扣除
                userAssetsService.subIntegralByUserId(totalCostNumSum, user.getId(), CoinCategoryEnum.INTEGRAL, AssetChangeLogEnum.IP_MALL_BUY, mallOrder.getId(), AssetChangeLogEnum.IP_MALL_BUY.getName());
                //插入订单关联兑换积分
                MallOrderExchange userAssetsOrder = new MallOrderExchange();
                userAssetsOrder.setOrderId(mallOrder.getId());
                userAssetsOrder.setOrderProductId(mallOrderProduct.getId());
                userAssetsOrder.setActivityId(mallOrderProduct.getActivityId());
                userAssetsOrder.setActivitySpecsId(mallOrderProduct.getActivitySpecsId());
                userAssetsOrder.setLinkName(MallExchangeEnum.INTEGRAL.getDesc());
                userAssetsOrder.setLinkId(userAssets.getId());
                userAssetsOrder.setType(MallExchangeEnum.INTEGRAL);
                userAssetsOrder.setCostNum(totalCostNumSum.intValue());
                userAssetsOrder.insert();
            }

            //校验权益道具
            List<MallActivityExchange> equityList = activityExchangeList.stream().filter(o -> o.getType() == MallExchangeEnum.EQUITY).collect(Collectors.toList());
            for (MallActivityExchange mallActivityExchange : equityList) {
                Integer costNum = mallActivityExchange.getCostNum();
                Long linkId = mallActivityExchange.getLinkId();

                int costNumSum = costNum * count;
                List<UserEquityProps> list = userEquityPropsService.getHavingListByUserIdAndEquityPropsIdAndLimit(user.getId(), linkId, costNumSum);
                Assert.isTrue(list.size() >= costNumSum, () -> new GlobalRunTimeException(ErrorCode.EQUITY_PROPS_NOT_ENOUGH));
                //扣除权益商品
                Assert.isTrue(userEquityPropsService.normalToconsumeByIds(list, user.getId(), UserEquityPropsUseTypeEnum.IP_MALL_BUY.getDescription(),
                        mallOrder.getId(), UserEquityPropsUseTypeEnum.IP_MALL_BUY), () -> new GlobalRunTimeException(ErrorCode.FAILED_TO_OBTAIN_EQUITY_PROPS));

                for (UserEquityProps userEquityProps : list) {
                    MallOrderExchange userEquityPropsOrder = new MallOrderExchange();
                    userEquityPropsOrder.setOrderId(mallOrder.getId());
                    userEquityPropsOrder.setOrderProductId(mallOrderProduct.getId());
                    userEquityPropsOrder.setActivityId(mallOrderProduct.getActivityId());
                    userEquityPropsOrder.setActivitySpecsId(mallOrderProduct.getActivitySpecsId());
                    userEquityPropsOrder.setLinkName(userEquityProps.getFirstTitle());
                    userEquityPropsOrder.setLinkId(userEquityProps.getId());
                    userEquityPropsOrder.setType(MallExchangeEnum.EQUITY);
                    userEquityPropsOrder.setCostNum(1);
                    userEquityPropsOrder.insert();
                }
            }

            //校验NFT
            List<MallActivityExchange> nftList = activityExchangeList.stream().filter(o -> o.getType() == MallExchangeEnum.NFT).collect(Collectors.toList());
            for (MallActivityExchange mallActivityExchange : nftList) {
                int costNum = mallActivityExchange.getCostNum();
                Long linkId = mallActivityExchange.getLinkId();

                costNum = costNum * count;
                List<UserCollection> userCollectionList = userCollectionService.getUserCollectionListByCollectionIdAndUserIdAndSize(linkId, user.getId(), costNum);
                Assert.isTrue(userCollectionList.size() >= costNum, () -> new GlobalRunTimeException(ErrorCode.MALL_DOES_NOT_MEET_THE_REDEMPTION_CONDITIONS));
                daoChainInfoService.transactionNft(mallOrder, userCollectionList, mallOrderProduct);
            }
            //修改为待发货
            mallOrder.setStatus(MallOrderStatusEnum.WAIT_RECEIPT);
            mallOrder.setPayTime(DateTime.now());
            mallOrder.updateById();

            createMallOrderVO.setStatus(MallOrderStatusEnum.WAIT_RECEIPT);

            //累计用户兑换金额
            if (mallActivity.getBuyLimitType() == MallBuyLimitTypeEnum.DYNAMIC) {
                mallUserActivitySummaryService.updateTotalExchangeAmount(user.getId(), mallActivity.getExchangeAmount().multiply(Convert.toBigDecimal(count)).setScale(2, BigDecimal.ROUND_DOWN));
            }

            //日志
            MallOrderStatusLog orderStatusLog = new MallOrderStatusLog();
            orderStatusLog.setMallOrderId(mallOrder.getId());
            orderStatusLog.setChangeType(MallOrderStatusEnum.WAIT_RECEIPT.toString());
            orderStatusLog.setChangeMessage(MallOrderStatusEnum.WAIT_RECEIPT.getDescription());
            orderStatusLog.setRemark("兑换时间");
            orderStatusLog.insert();
        }

        return createMallOrderVO;
    }

    @Override
    public Page<PageMallOrderVO> pageMallOrder(Long userId, ActivityTypeEnum activityType, Integer queryStatus, Integer pageNo, Integer pageSize, SourceEnum sourceEnum, Long wxMiniUserId) {
        Page<PageMallOrderVO> page = mallOrderDao.pageMallOrder(userId, activityType.getCode(), queryStatus, new Page<>(pageNo, pageSize), sourceEnum, wxMiniUserId);
        for (PageMallOrderVO record : page.getRecords()) {
            //处理商品信息
            List<MallOrderProduct> list = mallOrderProductService.getListByOrderId(record.getId());
            List<MallOrderProductDetailsVO> productList = list.stream().map(mallOrderProduct -> {
                MallOrderProductDetailsVO mallOrderProductDetailsVO = BeanUtil.copyProperties(mallOrderProduct, MallOrderProductDetailsVO.class);
                mallOrderProductDetailsVO.setProductSalesPrice(mallOrderProduct.getProductSalesPrice());
                mallOrderProductDetailsVO.setOrderProductId(mallOrderProduct.getId());

                if (mallOrderProduct.getActivityType() == ActivityTypeEnum.EXCHANGE) {
                    if (activityType == ActivityTypeEnum.EXCHANGE) {
                        List<MallOrderDetailsExchangeVO> exchangeList = mallOrderExchangeDao.getExchangeListVOByOrderPorductId(mallOrderProduct.getId());
                        // 把对象exchangeVOList进行分组处理,把相同数据的放到一起,把字段costNum相加
                        Map<MallExchangeEnum, List<MallOrderDetailsExchangeVO>> map = exchangeList.stream().collect(Collectors.groupingBy(MallOrderDetailsExchangeVO::getType));
                        List<MallOrderDetailsExchangeVO> info = new ArrayList<>();
                        for (Map.Entry<MallExchangeEnum, List<MallOrderDetailsExchangeVO>> entry : map.entrySet()) {
                            MallOrderDetailsExchangeVO mallOrderDetailsExchangeVO = new MallOrderDetailsExchangeVO();
                            // 判断不为空
                            mallOrderDetailsExchangeVO.setLinkName(CollUtil.isNotEmpty(entry.getValue()) ? entry.getValue().get(0).getLinkName() : null);
                            mallOrderDetailsExchangeVO.setType(entry.getKey());
                            mallOrderDetailsExchangeVO.setCostNum(entry.getValue().stream().mapToInt(MallOrderDetailsExchangeVO::getCostNum).sum());
                            info.add(mallOrderDetailsExchangeVO);
                        }
                        if (CollUtil.isNotEmpty(info)) {
                            mallOrderProductDetailsVO.setExchangeList(info);
                        } else {
                            mallOrderProductDetailsVO.setExchangeList(Lists.newArrayList());
                        }
                    }
                }
                return mallOrderProductDetailsVO;
            }).collect(Collectors.toList());
            record.setProductList(productList);
            Boolean isAfterSale = mallOrderRefundService.whetherTheAfterSalesOrderExists(record.getId());
            record.setIsAfterSale(isAfterSale);
            if (record.getIsVirtual()) {
                ApiOrderDirect apiOrderDirect = apiOrderDirectService.getByOrderId(record.getId());
                if (Objects.nonNull(apiOrderDirect)) {
                    record.setApiOrderState(apiOrderDirect.getApiOrderState());
                }
            }
        }
        return page;
    }

    @Override
    public Page<PageMallPopularizeOrderVO> pageMallPopularizeOrder(UserInfo user, Integer incomeStatus, Integer pageNo, Integer pageSize) {
        Page<PageMallPopularizeOrderVO> page = mallOrderDao.pageMallPopularizeOrder(user.getId(), incomeStatus, new Page<>(pageNo, pageSize));
        for (PageMallPopularizeOrderVO record : page.getRecords()) {
            //处理商品信息
            List<MallOrderProduct> list = mallOrderProductService.getListByOrderId(record.getId());
            List<MallOrderProductDetailsVO> productList = list.stream().map(mallOrderProduct -> {
                MallOrderProductDetailsVO mallOrderProductDetailsVO = BeanUtil.copyProperties(mallOrderProduct, MallOrderProductDetailsVO.class);
                mallOrderProductDetailsVO.setProductSalesPrice(mallOrderProduct.getProductSalesPrice());
                mallOrderProductDetailsVO.setOrderProductId(mallOrderProduct.getId());
                return mallOrderProductDetailsVO;
            }).collect(Collectors.toList());
            record.setProductList(productList);
        }

        return page;
    }

    @Override
    public MallOrderDetailsVO mallOrderDetails(Long userId, Long id, SourceEnum source, Long wxMiniUserId) {
        MallOrder mallOrder = mallOrderDao.getOrderByIdAndUserId(id, userId, source, wxMiniUserId);
        //订单不存在
        Assert.notNull(mallOrder, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));

        MallOrderDetailsVO mallOrderDetailsVO = BeanUtil.copyProperties(mallOrder, MallOrderDetailsVO.class);
        mallOrderDetailsVO.setWishBalancePrice(mallOrder.getWishBalancePrice());
        mallOrderDetailsVO.setPayBalancePrice(mallOrder.getPayBalancePrice());
        mallOrderDetailsVO.setPayWalletPrice(mallOrder.getPayWalletPrice());
        mallOrderDetailsVO.setIsVirtual(mallOrder.getIsVirtual());
        mallOrderDetailsVO.setIsRefund(Boolean.FALSE);
        mallOrderDetailsVO.setDeliveryNo(StrUtil.isBlank(mallOrder.getDeliveryNo()) ? "0" : mallOrder.getDeliveryNo());
        mallOrderDetailsVO.setNowTimeStamp(DateTime.now().getTime());
        if (mallOrder.getIsVirtual()) {
            ApiOrderDirect apiOrderDirect = apiOrderDirectService.getByOrderId(id);
            if (Objects.nonNull(apiOrderDirect)) {
                mallOrderDetailsVO.setApiOrderDirectDTO(ApiOrderDirectDTO.build(apiOrderDirect));
            }
        }

        //如果是待付款状态下 就计算过期时间的时间戳
        if (mallOrderDetailsVO.getStatus() == MallOrderStatusEnum.WAIT_PAY) {
            mallOrderDetailsVO.setExpiredTimeStamp(mallOrderDetailsVO.getExpiredTime().getTime());
        }
        //处理收货地址 -> 姓名,电话,省,市,区,详细地址
        mallOrderDetailsVO.setUserAddr(StrUtil.format("{},{},{},{},{},{}", mallOrder.getUserRealName(), mallOrder.getUserTel(), mallOrder.getProvince(), mallOrder.getCity(), mallOrder.getArea(), mallOrder.getUserAddress()));

        //获取商品信息
        List<MallOrderProduct> productList = mallOrderProductService.getListByOrderId(id);
        Assert.isFalse(productList.size() == 0, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));

        //处理商品信息
        List<MallOrderProductDetailsVO> productDetailsList = productList.stream()
                .map(product -> {
                    MallOrderProductDetailsVO mallOrderProductDetailsVO = BeanUtil.copyProperties(product, MallOrderProductDetailsVO.class);
                    mallOrderProductDetailsVO.setOrderProductId(product.getId());
                    mallOrderProductDetailsVO.setProductSalesPrice(product.getProductSalesPrice());
                    MallProduct productById = mallProductService.getById(product.getProductId());
                    if (Objects.nonNull(productById)) {
                        mallOrderProductDetailsVO.setProductDetail(StrUtil.split(productById.getProductDetail(), ","));
                    }
                    return mallOrderProductDetailsVO;
                }).collect(Collectors.toList());
        mallOrderDetailsVO.setProductList(productDetailsList);

        //获取订单时间信息
        List<MallOrderStatusLog> statusLogList = mallOrderStatusLogService.getListByOrderId(id);
        List<MallOrderStatusVO> statusList = statusLogList.stream().map(statusLog -> {
            MallOrderStatusVO mallOrderStatusVO = BeanUtil.copyProperties(statusLog, MallOrderStatusVO.class);
            return mallOrderStatusVO;
        }).collect(Collectors.toList());
        if (statusList.size() > 0) {
            //退款成功并且是全部退款
            MallOrderRefundStatusEnum refundStatus = mallOrder.getRefundStatus();
            if (refundStatus == MallOrderRefundStatusEnum.NEW_APPLYING) {
                // 是否有售后单
                int sumRefundSuccessCount = productList.stream().mapToInt(MallOrderProduct::getRefundSuccessCount).sum();
                if (mallOrder.getTotalNum() <= sumRefundSuccessCount) {
                    // 售后全部退款时间
                    MallOrderStatusLog statusLog = mallOrderStatusLogService.getOneByOrderIdAndChangeType(mallOrder.getId(), MallOrderStatusEnum.CLOSURE.toString());
                    if (Objects.nonNull(statusLog)) {
                        MallOrderStatusVO mallOrderStatusVO = BeanUtil.copyProperties(statusLog, MallOrderStatusVO.class);
                        mallOrderStatusVO.setRemark("交易关闭时间");
                        statusList.add(mallOrderStatusVO);
                    }
                }
            } else {
                if (mallOrder.getRefundStatus() == MallOrderRefundStatusEnum.REFUND_SUCCES) {
                    int sumRefundSuccessCount = productList.stream().mapToInt(MallOrderProduct::getRefundSuccessCount).sum();
                    if (mallOrder.getTotalNum() <= sumRefundSuccessCount) {
                        MallOrderStatusLog statusLog = mallOrderStatusLogService.getOneByOrderIdAndChangeType(mallOrder.getId(), MallOrderRefundStatusEnum.REFUND_SUCCES.name());
                        MallOrderStatusVO mallOrderStatusVO = BeanUtil.copyProperties(statusLog, MallOrderStatusVO.class);
                        mallOrderStatusVO.setRemark("交易关闭时间");
                        statusList.add(mallOrderStatusVO);
                    }
                }
            }


        }
        mallOrderDetailsVO.setStatusList(statusList);

        //客服微信
        UserCreatorInfo userCreatorInfo = userCreatorInfoService.getById(mallOrder.getDaoId());
        mallOrderDetailsVO.setCustomerServiceUrl(ObjectUtil.isNull(userCreatorInfo.getCustomerServiceUrl()) ? StrUtil.EMPTY : userCreatorInfo.getCustomerServiceUrl());


        //是否可以申请售后
        //订单状态 :  待付款,待发货,待收货,已完成(未超过7天)
        //售后状态 :  未申请,拒绝退款,取消退款
        if (mallOrder.getActivityType() == ActivityTypeEnum.SALES) {//购买的订单
            if (mallOrder.getIsVirtual()) {
                // 虚拟商品
                // 虚拟订单 只有当直充订单充值失败才可申请售后
                ApiOrderDirect apiOrderDirect = apiOrderDirectService.getByOrderId(mallOrder.getId());
                if ("failed".equals(apiOrderDirect.getApiOrderState())) {
                    mallOrderDetailsVO.setIsRefund(Boolean.TRUE);
                }
            } else {
                if (MallOrderStatusEnum.getIsRefundStatus().contains(mallOrder.getStatus())) {//订单状态
                    mallOrderDetailsVO.setIsRefund(Boolean.TRUE);
                }
            }
            //订单已完成超过7天,不可申请售后
            if (mallOrder.getStatus() == MallOrderStatusEnum.FINISH) {
                MallOrderStatusLog mallOrderStatusLog = mallOrderStatusLogService.getOneByOrderIdAndChangeType(mallOrder.getId(), MallOrderStatusEnum.FINISH.toString());
                DateTime dateTime = DateUtil.offsetDay(mallOrderStatusLog.getCreateTime(), 7);
                if (DateTime.now().isAfter(dateTime)) {
                    mallOrderDetailsVO.setIsRefund(Boolean.FALSE);
                    log.info("订单已完成超过7天,不可申请售后,订单id:{}", mallOrder.getId());
                }
            }
            // 判断是否拥有新售后单
            MallOrderRefundStatusEnum refundStatus = mallOrder.getRefundStatus();
            if (refundStatus == MallOrderRefundStatusEnum.NEW_APPLYING) {
                for (MallOrderProduct mallOrderProduct : productList) {
                    Integer refundNum = mallOrderProduct.getRefundNum();
                    // 已经申请商品数量
                    if (mallOrderProduct.getProductNum() <= refundNum) {
                        mallOrderDetailsVO.setIsRefund(Boolean.FALSE);
                        break;
                    }
                }
            }
            // 售后
            List<MallOrderRefundDTO> mallOrderRefundDTOS = mallOrderRefundService.getRefundListByOrderId(id);
            mallOrderDetailsVO.setMallOrderRefundDTOList(mallOrderRefundDTOS);
        }

        //售后状态
        mallOrderDetailsVO.setRefundStatus(mallOrder.getRefundStatus());
        //如果是活动兑换 则获取兑换信息
        if (mallOrder.getActivityType() == ActivityTypeEnum.EXCHANGE) {
            List<MallOrderExchange> exchangeList = mallOrderExchangeDao.getOrderExchangeListByOrderId(mallOrder.getId());

            List<MallOrderDetailsExchangeVO> exchangeVOList = exchangeList.stream().map(exchange -> {
                MallOrderDetailsExchangeVO mallOrderDetailsExchangeVO = BeanUtil.copyProperties(exchange, MallOrderDetailsExchangeVO.class);
                return mallOrderDetailsExchangeVO;
            }).collect(Collectors.toList());
            // 把对象exchangeVOList进行分组处理,把相同数据的放到一起,把字段costNum相加
            Map<MallExchangeEnum, List<MallOrderDetailsExchangeVO>> map = exchangeVOList.stream().collect(Collectors.groupingBy(MallOrderDetailsExchangeVO::getType));
            List<MallOrderDetailsExchangeVO> list = new ArrayList<>();
            for (Map.Entry<MallExchangeEnum, List<MallOrderDetailsExchangeVO>> entry : map.entrySet()) {
                if (entry.getKey() == MallExchangeEnum.EQUITY) {
                    if (!CollectionUtils.isEmpty(entry.getValue())) {
                        list.addAll(entry.getValue());
                    }
                } else {
                    MallOrderDetailsExchangeVO mallOrderDetailsExchangeVO = new MallOrderDetailsExchangeVO();
                    // 判断不为空
                    mallOrderDetailsExchangeVO.setLinkName(CollUtil.isNotEmpty(entry.getValue()) ? entry.getValue().get(0).getLinkName() : null);
                    mallOrderDetailsExchangeVO.setType(entry.getKey());
                    mallOrderDetailsExchangeVO.setCostNum(entry.getValue().stream().mapToInt(MallOrderDetailsExchangeVO::getCostNum).sum());
                    list.add(mallOrderDetailsExchangeVO);
                }
            }
            mallOrderDetailsVO.setExchangeList(list);
        } else {
            mallOrderDetailsVO.setExchangeList(Lists.newArrayList());
        }
        //是否可以修改收货地址,非虚拟订单,待收货，并且没修改过地址
        if (!mallOrder.getIsVirtual() && mallOrder.getStatus() == MallOrderStatusEnum.WAIT_RECEIPT) {
            Integer count = mallOrderUpdateAddressLogDao.countByOrderId(mallOrder.getId());
            if (count == null || count == 0) {
                mallOrderDetailsVO.setCanEditAddr(Boolean.TRUE);
            }
        }
        return mallOrderDetailsVO;
    }


    @Override
    public void updateStatusById(Long orderId, MallOrderStatusEnum status) {
        Assert.isTrue(mallOrderDao.updateStatusById(orderId, status), () -> new GlobalRunTimeException(ErrorCode.CLOSING_FAILED_PLEASE_TRY_AGAIN_LATER));
        //日志
        MallOrderStatusLog mallOrderStatusLog = new MallOrderStatusLog();
        mallOrderStatusLog.setMallOrderId(orderId);
        mallOrderStatusLog.setChangeType(status.toString());
        mallOrderStatusLog.setChangeMessage(status.getDescription());

        if (status == MallOrderStatusEnum.TIMEOUT_CANCEL) {
            mallOrderStatusLog.setRemark("交易关闭时间");
        }
        if (status == MallOrderStatusEnum.WAIT_RECEIPT) {
            mallOrderStatusLog.setRemark("付款时间");
        }
        if (status == MallOrderStatusEnum.TO_BE_RECEIPT) {
            mallOrderStatusLog.setRemark("发货时间");
        }
        if (status == MallOrderStatusEnum.RECEIPT || status == MallOrderStatusEnum.FINISH) {
            mallOrderStatusLog.setRemark("交易完成时间");
        }

        mallOrderStatusLog.insert();

        //如果是已完成状态下 则更新收益订单的收益时间 确认收货7天后
        if (status == MallOrderStatusEnum.FINISH) {
            MallOrder order = mallOrderDao.getById(orderId);
            log.info("订单收货. 收货数据信息----订单数据:{}", JSON.toJSON(order));
            if (order.getActivityType() == ActivityTypeEnum.SALES && !order.getIsVirtual()) {
                //累计消费金额
                BigDecimal consumptionAmount = order.getPayPrice().subtract(order.getWishBalancePrice()).subtract(order.getRefundPrice());
                Date payTime = order.getPayTime();
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date targetTime;
                try {
                    targetTime = dateFormat.parse(TARGETTIMESTRING);
                } catch (ParseException e) {
                    throw new RuntimeException(e);
                }
                if (consumptionAmount.compareTo(BigDecimal.ZERO) > 0 && targetTime.before(payTime)) {
                    try {
                        mallUserActivitySummaryService.updateTotalConsumptionAmount(order.getUserId(), consumptionAmount);
                        //更新排行榜数据
                        mallUserActivityRankingDetailService.saveOrUpdate(order.getUserId(), consumptionAmount, null, new Date());
                        //更新道具释放状态
                        mallUserPropsRewardsDetailService.confirm(orderId, consumptionAmount);
                    } catch (Exception e) {
                        log.error("ranking save or update error", e);
                    }
                }
                //查询这个订单是否有收益订单
                List<MallOrderIncome> orderIncomeList = mallOrderIncomeDao.getListByOrderId(orderId);
                for (MallOrderIncome mallOrderIncome : orderIncomeList) {
                    log.info("订单id:{},状态:{},售后状态:{},收益金额:{}", orderId, status, order.getRefundStatus(), mallOrderIncome.getRealIncomePrice());
                    if (NumberUtil.isGreater(mallOrderIncome.getRealIncomePrice(), BigDecimal.ZERO)) {
                        log.info("收货成功,修改状态开始");
                        String mallOrderFinishDay = staticDataDao.getByType("mall_order_finish_day").getValue();
                        mallOrderIncomeDao.updateIsEfficient(mallOrderIncome.getId(), DateUtil.offsetDay(DateTime.now(), Integer.valueOf(mallOrderFinishDay)), Boolean.TRUE);
                        log.info("收货成功,修改状态结束.修改成功修改数据内容------{}", JSON.toJSON(mallOrderIncome));
                    }
                }
            }
        }
    }

    @Override
    public List<MallOrder> getTimeOutMallOrder() {
        return mallOrderDao.getTimeOutMallOrder();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean autoCloseOrder(MallOrder order) throws GlobalException {
        List<MallOrderProduct> mallOrderProductList = mallOrderProductService.getListByOrderId(order.getId());
        if (CollectionUtils.isEmpty(mallOrderProductList)) {
            return Boolean.FALSE;
        }
        MallOrderProduct orderProduct = mallOrderProductList.get(0);
        RLock lock = redisson.getLock(RedisKeyEnum.IP_PRODUCT_STOCK_LOCK.getKey() + orderProduct.getActivityId());
        try {
            boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {

                MallMemberEquityUseRecord mallMemberEquityUseRecord = mallMemberEquityUseRecordService.getByOrderId(order.getId());
                if (Objects.nonNull(mallMemberEquityUseRecord)) {
                    Assert.isTrue(mallMemberEquityTargetDao.addCanUseNum(mallMemberEquityUseRecord.getMallMemberEquityTargetId(), order.getTotalNum()), () -> new GlobalRunTimeException(ErrorCode.ABNORMAL_REDUCTION_IN_MEMBER_EQUITY_INVENTORY));
                    Assert.isTrue(mallMemberEquityUseRecordService.deleteById(mallMemberEquityUseRecord.getId()), () -> new GlobalRunTimeException(ErrorCode.THE_NUMBER_OF_MEMBER_BENEFITS_IS_ABNORMAL));
                }
                for (MallOrderProduct mallOrderProduct : mallOrderProductList) {
                    Assert.isTrue(mallActivitySpecsService.subFrozenCount(mallOrderProduct.getActivitySpecsId(), mallOrderProduct.getProductNum()), () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_STOCK_INSUFFICIENT));
                    //修改订单为已关闭
                    updateStatusById(order.getId(), MallOrderStatusEnum.TIMEOUT_CANCEL);
                }

            } else {
                throw new GlobalException("当前人数过多，请稍后再试");
            }
        } catch (InterruptedException e) {
            throw new GlobalException("当前人数过多，请稍后再试");
        } finally {
            lock.unlock();
        }
        return Boolean.FALSE;
    }

    @Override
    public void cancelOrderById(Long orderId, Long userId, SourceEnum source, Long wxMiniUserId) throws GlobalException {
        MallOrder order = mallOrderDao.getOrderByIdAndUserId(orderId, userId, source, wxMiniUserId);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        Assert.isTrue(MallOrderStatusEnum.WAIT_PAY.equals(order.getStatus()), () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_STATUS_ERROR));
        //关闭订单
        autoCloseOrder(order);
    }

    @Override
    public List<MallOrder> getAutoConfirmMallOrder(Integer day) {
        return mallOrderDao.getAutoConfirmMallOrder(day);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void autoConfirmOrder(MallOrder order, Integer confirmDay) throws GlobalException {
        //查询发货的时间
        MallOrderStatusLog statusLog = mallOrderStatusLogService.getOneByOrderIdAndChangeType(order.getId(), MallOrderStatusEnum.TO_BE_RECEIPT.toString());
        DateTime dateTime = DateUtil.offsetDay(statusLog.getCreateTime(), confirmDay);
        if (DateTime.now().isAfter(dateTime)) {
            //修改为订单完成
            updateStatusById(order.getId(), MallOrderStatusEnum.FINISH);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmOrderById(Long orderId, Long userId, SourceEnum source, Long wxMiniUserId) throws GlobalException {
        MallOrder order = mallOrderDao.getOrderByIdAndUserId(orderId, userId, source, wxMiniUserId);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        Assert.isTrue(order.getStatus() == MallOrderStatusEnum.TO_BE_RECEIPT, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_STATUS_ERROR));
        //修改为订单完成
        updateStatusById(order.getId(), MallOrderStatusEnum.FINISH);
    }

    @Override
    public MallOrder getById(Long orderId) {
        return mallOrderDao.getById(orderId);
    }

    @Override
    public MallOrder getByOrderNo(String orderNo) {
        return mallOrderDao.getByOrderNo(orderNo);
    }

    @Override
    public RefundInfoVO getRefundReason(Long id, Long orderProductId) {
        MallOrder order = mallOrderDao.getById(id);
        //校验售后订单
        MallOrderProduct mallOrderProduct = checkRefundOrder(order, orderProductId);
        RefundInfoVO refundInfoVO = new RefundInfoVO();
        refundInfoVO.setRefundPrice(mallOrderProduct.getProductSalesPrice());
        refundInfoVO.setOrderId(order.getId());
        refundInfoVO.setOrderProductId(mallOrderProduct.getId());
        refundInfoVO.setMaxCount(mallOrderProduct.getProductNum() - mallOrderProduct.getRefundNum());

        refundInfoVO.setRefundReasonList(RefundReasonEnum.getRefundReasonList());
        if (order.getIsVirtual()) {
            // 虚拟商品仅支持仅退款
            refundInfoVO.setOrderRefundTypeList(MallOrderRefundTypeEnum.getVirtualMallOrderRefundTypeList());
        } else {
            refundInfoVO.setOrderRefundTypeList(MallOrderRefundTypeEnum.getMallOrderRefundTypeList());
        }
        List<MallOrderIncome> orderIncomeList = mallOrderIncomeDao.getListByOrderId(order.getId());
        for (MallOrderIncome mallOrderIncome : orderIncomeList) {
            mallOrderIncome.setIsEfficient(Boolean.FALSE);
            mallOrderIncome.updateById();
        }

        return refundInfoVO;
    }

    @Override
    public RefundValuationVO getRefundValuation(Long id, Long orderProductId, Integer count) {
        MallOrder order = mallOrderDao.getById(id);
        //校验售后订单
        MallOrderProduct mallOrderProduct = checkRefundOrder(order, orderProductId);

        Integer sumCount = count + mallOrderProduct.getRefundSuccessCount();
        if (mallOrderProduct.getProductNum() < sumCount) {
            throw new GlobalRunTimeException(ErrorCode.MALL_ORDER_PRODUCT_NUM_ERROR);
        }

        RefundValuationVO refundValuationVO = new RefundValuationVO();
        refundValuationVO.setRefundPrice(Convert.toBigDecimal(mallOrderProduct.getProductSalesPrice()).multiply(Convert.toBigDecimal(count)));

        return refundValuationVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long applyRefund(Long id, Long orderProductId, Integer count, RefundReasonEnum refundReason, MallOrderRefundTypeEnum refundType, String imgUrl, String description, String contactNumber) {
        if (StrUtil.isNotBlank(imgUrl)) {
            String[] split = imgUrl.split(",");
            if (split.length > 9) {
                throw new GlobalRunTimeException("最多上传9张图片");
            }
        }
        MallOrder order = mallOrderDao.getById(id);
        if (MallOrderRefundTypeEnum.REFUNDS == refundType || MallOrderRefundTypeEnum.EXCHANGE == refundType) {
            Assert.isTrue(MallOrderStatusEnum.getSecondIsRefundStatus().contains(order.getStatus()), () -> new GlobalRunTimeException(ErrorCode.THIS_ORDER_CANNOT_INITIATE_THIS_TYPE_OF_AFTER_SALE));
        }

        //校验售后订单
        MallOrderProduct mallOrderProduct = checkRefundOrder(order, orderProductId);
        // 退款数量
        Integer refundNum = mallOrderProduct.getRefundNum();
        Integer sumCount = count + refundNum;
        if (mallOrderProduct.getProductNum() < sumCount) {
            throw new GlobalRunTimeException(ErrorCode.MALL_ORDER_PRODUCT_NUM_ERROR);
        }
        // 获取订单的有效金额售后订单
        List<MallOrderRefund> orderRefunds = mallOrderRefundService.getAmountInForceListByOrderId(order.getId());
        // 获取退款数量和商品数量的比例
        BigDecimal divide = BigDecimalUtils.divide(count, mallOrderProduct.getProductNum());
        BigDecimal refundPrice = BigDecimalUtils.multiplys(order.getRealPrice(), divide);
        if (CollectionUtils.isEmpty(orderRefunds)) {
            // 无售后第一次售后
            if (BigDecimalUtils.compareTo(refundPrice, order.getRealPrice())) {
                // 售后价格大于订单实付金额
                refundPrice = order.getRealPrice();
            }
        } else {
            // 已发起售后退款总额
            BigDecimal oldRefundAmountTotal = orderRefunds.stream().map(o -> o.getRefundAmount()).reduce(BigDecimal::add).get();
            // 合计
            BigDecimal newRefundAmountTotal = BigDecimalUtils.add(oldRefundAmountTotal, refundPrice);
            if (BigDecimalUtils.compareTo(newRefundAmountTotal, order.getRealPrice())) {
                // 售后价格大于订单实付金额
                refundPrice = BigDecimalUtils.subtract(order.getRealPrice(), oldRefundAmountTotal);
            }
        }

        order.setRefundStatus(MallOrderRefundStatusEnum.NEW_APPLYING);
        order.setRefundType(refundType);
        order.setRefundReasonWap(refundReason.getDescription());
        order.setRefundReasonWapImg(imgUrl);
        order.setRefundReasonTime(DateTime.now());
        order.setRefundPrice(BigDecimalUtils.add(refundPrice, order.getRefundPrice()));
        order.updateById();

        mallOrderProduct.setRefundPrice(BigDecimalUtils.add(mallOrderProduct.getRefundPrice(), refundPrice));
        mallOrderProduct.setRefundNum(count + refundNum);
        mallOrderProduct.updateById();

        // 售后单
        MallOrderRefund mallOrderRefund = MallOrderRefund.build(order, mallOrderProduct, refundType, count, refundReason, description, imgUrl, contactNumber, refundPrice);
        mallOrderRefund.insert();
        // 创建售后单操作记录
        mallOrderRefundStatusLogService.create(mallOrderRefund.getId(), MallRefundStatusEnum.APPLYING, "待商家处理");
        if (SourceEnum.META_APP == order.getOrderSource()) {
            //售后订单收益失效
            mallOrderIncomeDao.getListByOrderId(order.getId()).forEach(mallOrderIncome -> {
                mallOrderIncome.setIsEfficient(Boolean.FALSE);
                mallOrderIncome.updateById();
            });
        }
        return mallOrderRefund.getId();
    }

    @Override
    public RefundDetailsVO refundDetails(Long id, Long orderProductId) {
        MallOrder order = mallOrderDao.getById(id);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        Assert.isFalse(order.getRefundStatus() == MallOrderRefundStatusEnum.NOT_APPLY, () -> new GlobalRunTimeException(ErrorCode.AFTERMARKET_ORDER_NOT_FOUND));

        MallOrderProduct mallOrderProduct = mallOrderProductService.getById(orderProductId);
        Assert.notNull(mallOrderProduct, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_PRODUCT_DOES_NOT_EXIST));

        RefundDetailsVO refundDetailsVO = new RefundDetailsVO();
        refundDetailsVO.setId(order.getId());
        refundDetailsVO.setOrderProductId(mallOrderProduct.getId());
        refundDetailsVO.setCount(mallOrderProduct.getRefundNum());

        refundDetailsVO.setRefundReason(order.getRefundReason());
        refundDetailsVO.setRefundReasonWap(order.getRefundReasonWap());
        refundDetailsVO.setRefundType(order.getRefundType());
        refundDetailsVO.setImgUrl(order.getRefundReasonWapImg());
        refundDetailsVO.setThumbnail(mallOrderProduct.getThumbnail());
        refundDetailsVO.setRefundStatus(order.getRefundStatus());
        refundDetailsVO.setRefundPrice(order.getRefundPrice());


        Boolean isCancel = Boolean.FALSE;
        if (order.getRefundStatus() == MallOrderRefundStatusEnum.NEW_APPLYING) {
            isCancel = Boolean.TRUE;
        }
        refundDetailsVO.setIsCancel(isCancel);
        return refundDetailsVO;
    }

    @Override
    public void cancelApplyRefund(Long id, Long orderProductId) {
        MallOrder order = mallOrderDao.getById(id);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        Assert.isTrue(order.getRefundStatus() == MallOrderRefundStatusEnum.APPLYING, () -> new GlobalRunTimeException(ErrorCode.INCORRECT_AFTER_SALES_STATUS));

        MallOrderProduct mallOrderProduct = mallOrderProductService.getById(orderProductId);
        Assert.notNull(mallOrderProduct, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_PRODUCT_DOES_NOT_EXIST));

        order.setRefundStatus(MallOrderRefundStatusEnum.CANCEL);
        order.updateById();

        MallOrderStatusLog mallOrderStatusLog = new MallOrderStatusLog();
        mallOrderStatusLog.setMallOrderId(order.getId());
        mallOrderStatusLog.setChangeType(MallOrderRefundStatusEnum.CANCEL.toString());
        mallOrderStatusLog.setChangeMessage(MallOrderRefundStatusEnum.CANCEL.getDescription());
        mallOrderStatusLog.setIsRefund(Boolean.TRUE);
        mallOrderStatusLog.setRemark("用户已撤销售后");
        mallOrderStatusLog.insert();

        //售后订单收益生效
        mallOrderIncomeDao.getListByOrderId(order.getId()).forEach(mallOrderIncome -> {
            mallOrderIncome.setIsEfficient(Boolean.TRUE);
            mallOrderIncome.updateById();
        });

    }

    /**
     * 退款记录
     *
     * @param id
     * @return
     */
    @Override
    public List<RefundRecordVO> refundRecord(Long id) {
        MallOrderRefund mallOrderRefund = mallOrderRefundService.getById(id);
        Assert.notNull(mallOrderRefund, () -> new GlobalRunTimeException(ErrorCode.THE_AFTER_SALES_ORDER_DOES_NOT_EXIST));
        List<RefundRecordVO> list = Lists.newArrayList();
        List<MallOrderRefundStatusLog> orderRefundStatusLogList = mallOrderRefundStatusLogService.getListByOrderRefundId(id);
        Date now = new Date();
        if (!CollectionUtils.isEmpty(orderRefundStatusLogList)) {
            MallOrderRefundStatusLog refundStatusLog = orderRefundStatusLogList.get(0);
            RefundRecordVO refundRecordVO = BeanUtil.copyProperties(refundStatusLog, RefundRecordVO.class);
            if (MallRefundStatusEnum.REFUSE_REFUND.name().equals(refundStatusLog.getChangeType())) {
                refundRecordVO.setRemark(mallOrderRefund.getRemark());
            } else if (MallRefundStatusEnum.REFUNDING.toString().equals(refundStatusLog.getChangeType())) {
                refundRecordVO.setRemark(MallRefundStatusEnum.REFUNDING.getRemark());
            } else if (MallRefundStatusEnum.REFUND_SUCCES.toString().equals(refundStatusLog.getChangeType())) {
                refundRecordVO.setRemark(MallRefundStatusEnum.REFUND_SUCCES.getRemark());
            } else if (MallRefundStatusEnum.CANCEL.toString().equals(refundStatusLog.getChangeType())) {
                refundRecordVO.setRemark(MallRefundStatusEnum.CANCEL.getRemark());
            } else if (MallRefundStatusEnum.RETURNING_GOODS.toString().equals(refundStatusLog.getChangeType())) {
                refundRecordVO.setRemark(MallRefundStatusEnum.RETURNING_GOODS.getRemark());
            } else if (MallRefundStatusEnum.EXCHANGING_GOODS.toString().equals(refundStatusLog.getChangeType())) {
                refundRecordVO.setRemark(MallRefundStatusEnum.EXCHANGING_GOODS.getRemark());
            } else if (MallRefundStatusEnum.REPLACEMENT_TO_BE_RECEIVED.toString().equals(refundStatusLog.getChangeType())) {
                refundRecordVO.setRemark(MallRefundStatusEnum.REPLACEMENT_TO_BE_RECEIVED.getRemark());
            } else if (MallRefundStatusEnum.REPLACEMENT_COMPLETED.toString().equals(refundStatusLog.getChangeType())) {
                refundRecordVO.setRemark(MallRefundStatusEnum.REPLACEMENT_COMPLETED.getRemark());
            } else if (MallRefundStatusEnum.TO_BE_RETURNED.toString().equals(refundStatusLog.getChangeType())) {
                DateTime end = DateUtil.offsetDay(refundRecordVO.getCreateTime(), 7);
                refundRecordVO.setEndTime(end);
                refundRecordVO.setNowTime(now);
            } else if (MallRefundStatusEnum.APPLYING.toString().equals(refundStatusLog.getChangeType())) {
                DateTime endTime = DateUtil.offsetDay(refundRecordVO.getCreateTime(), 3);
                refundRecordVO.setEndTime(endTime);
                refundRecordVO.setNowTime(now);
                refundRecordVO.setRemark(MallRefundStatusEnum.APPLYING.getRemark());
            }
            list.add(refundRecordVO);
        }
        return list;
    }

    @Override
    public Page<AdminMallPageOrderVO> adminPageOrder(ActivityTypeEnum activityType, String orderNo, Date beginTime, Date endTime, Date payBeginTime, Date payEndTime, String productName, Integer status, Integer payType, Integer isRefund, String userTel, Integer pageNo, Integer pageSize, Long supplierId, String categoryName, SourceEnum orderSource) {
        Page<AdminMallPageOrderVO> adminMallPageOrderVOPage = mallOrderDao.adminPageOrder(activityType, orderNo, beginTime, endTime, payBeginTime, payEndTime, productName, status, payType, isRefund, userTel, pageNo, pageSize, supplierId, categoryName, orderSource);
        if (Objects.nonNull(adminMallPageOrderVOPage) && !CollectionUtils.isEmpty(adminMallPageOrderVOPage.getRecords())) {
            List<AdminMallPageOrderVO> records = adminMallPageOrderVOPage.getRecords();
            List<Long> activitySpecsIdList = records.stream().map(AdminMallPageOrderVO::getActivitySpecsId).distinct().collect(Collectors.toList());
            List<Long> productIdList = records.stream().map(AdminMallPageOrderVO::getProductId).distinct().collect(Collectors.toList());
            List<Long> orderIdList = records.stream().map(AdminMallPageOrderVO::getId).collect(Collectors.toList());
            List<MallActivitySpecsGetSendCodeDTO> sendCodeList = mallActivitySpecsService.getSendCodeByActivitySpecsIdList(activitySpecsIdList);
            List<SupplierManageBindingSpecsGetSupplyNameDTO> supplyNameList = supplierManageBindingDao.getSupplyNameByProductIdList(productIdList);
            List<MallOrderBillGetBillStatusDTO> orderbillStatusList = mallOrderBillDao.getOrderBillStatusByOrderIdList(orderIdList);
            List<MallOrderStatusLog> mallOrderStatusLogList = mallOrderStatusLogService.getListByOrderIdsAndChangeType(orderIdList, MallOrderStatusEnum.FINISH.name());
            Map<Long, String> sendCodeMap = new HashMap<>();
            Map<Long, String> supplyNameMap = new HashMap<>();
            Map<Long, Boolean> billStatusMap = new HashMap<>();
            Map<Long, Date> mallOrderStatusLogMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(sendCodeList)) {
                sendCodeMap = sendCodeList.stream().collect(Collectors.toMap(MallActivitySpecsGetSendCodeDTO::getActivitySpecsId, MallActivitySpecsGetSendCodeDTO::getSendCode));
            }
            if (!CollectionUtils.isEmpty(supplyNameList)) {
                supplyNameMap = supplyNameList.stream().collect(Collectors.toMap(SupplierManageBindingSpecsGetSupplyNameDTO::getProductId, SupplierManageBindingSpecsGetSupplyNameDTO::getSupplyName));

            }
            if (!CollectionUtils.isEmpty(orderbillStatusList)) {
                billStatusMap = orderbillStatusList.stream().collect(Collectors.toMap(MallOrderBillGetBillStatusDTO::getOrderId, MallOrderBillGetBillStatusDTO::getBillStatus));
            }
            if (!CollectionUtils.isEmpty(mallOrderStatusLogList)) {
                mallOrderStatusLogMap = mallOrderStatusLogList.stream().collect(Collectors.toMap(MallOrderStatusLog::getMallOrderId, MallOrderStatusLog::getCreateTime, (existing, replacement) -> existing));
            }
            for (AdminMallPageOrderVO record : records) {
                if (sendCodeMap.containsKey(record.getActivitySpecsId())) {
                    record.setSendCode(sendCodeMap.get(record.getActivitySpecsId()));
                }
                if (supplyNameMap.containsKey(record.getProductId())) {
                    record.setSupplyName(supplyNameMap.get(record.getProductId()));
                }
                if (billStatusMap.containsKey(record.getId())) {
                    record.setBillStatus(billStatusMap.get(record.getId()));
                }
                if (mallOrderStatusLogMap.containsKey(record.getId())) {
                    record.setFinishCreateTime(mallOrderStatusLogMap.get(record.getId()));
                }
            }

        }
        return adminMallPageOrderVOPage;
    }

    @Override
    public AdminOrderDetailsVO adminOrderDetails(Long orderId) {
        MallOrder order = mallOrderDao.getById(orderId);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        List<MallOrderProduct> list = mallOrderProductService.getListByOrderId(orderId);
        Assert.isFalse(list.size() == 0, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_PRODUCT_DOES_NOT_EXIST));

        //状态列表
        List<MallOrderStatusLog> statusLogList = mallOrderStatusLogService.getListByOrderIdGroupType(orderId);

        AdminOrderDetailsVO adminOrderDetailsVO = new AdminOrderDetailsVO();
        if (order.getIsVirtual()) {
            ApiOrderDirect apiOrderDirect = apiOrderDirectService.getByOrderId(orderId);
            if (Objects.nonNull(apiOrderDirect)) {
                adminOrderDetailsVO.setApiOrderDirect(ApiOrderDirectDTO.build(apiOrderDirect));
            }
        }
        //状态信息
        List<MallOrderStatusVO> statusList = statusLogList.stream().map(statusLog -> {
            MallOrderStatusVO mallOrderStatusVO = new MallOrderStatusVO();
            mallOrderStatusVO.setChangeType(statusLog.getChangeType().toString());
            mallOrderStatusVO.setCreateTime(statusLog.getCreateTime());
            mallOrderStatusVO.setRemark(statusLog.getRemark());
            return mallOrderStatusVO;
        }).collect(Collectors.toList());
        adminOrderDetailsVO.setStatusList(statusList);

        List<AdminMallOrderProductDetailsVO> productList = list.stream().map(MallOrderProduct -> {

            AdminMallOrderProductDetailsVO adminMallOrderProductDetailsVO = BeanUtil.copyProperties(MallOrderProduct, AdminMallOrderProductDetailsVO.class);
            adminMallOrderProductDetailsVO.setProfit(MallOrderProduct.getProductSalesPrice().subtract(MallOrderProduct.getProductCostPrice().setScale(2, BigDecimal.ROUND_DOWN)));
            adminMallOrderProductDetailsVO.setProductCostPrice(MallOrderProduct.getProductCostPrice());
            adminMallOrderProductDetailsVO.setProductSalesPrice(MallOrderProduct.getProductSalesPrice());


            MallActivitySpecs mallActivitySpecs = mallActivitySpecsService.getByIdWithoutDeleted(MallOrderProduct.getActivitySpecsId());
            Assert.isFalse(BeanUtil.isEmpty(mallActivitySpecs), () -> new GlobalRunTimeException(ErrorCode.INCORRECT_SPECIFICATION));
            MallProductSpecs mallProductSpecs = mallProductSpecsService.getByIdWithoutDeleted(mallActivitySpecs.getSpecsId());
            adminMallOrderProductDetailsVO.setSpecsCode(ObjectUtil.isNull(mallProductSpecs) ? StrUtil.EMPTY : mallProductSpecs.getSpecsCode());
            adminMallOrderProductDetailsVO.setSendCode(ObjectUtil.isNull(mallProductSpecs) ? StrUtil.EMPTY : mallProductSpecs.getSendCode());
            MallProduct mallProduct = mallProductService.getById(MallOrderProduct.getProductId());
            adminMallOrderProductDetailsVO.setProductCode(ObjectUtil.isNull(mallProduct) ? StrUtil.EMPTY : mallProduct.getProductCode());
            adminMallOrderProductDetailsVO.setActivityCostPrice(mallActivitySpecs.getActivityCostPrice());
            adminMallOrderProductDetailsVO.setReservePrice(mallActivitySpecs.getReservePrice());
            adminMallOrderProductDetailsVO.setActivityProfit(mallActivitySpecs.getProfit());
            if (Objects.nonNull(mallActivitySpecs.getProfitTemplateId())) {
                adminMallOrderProductDetailsVO.setProfitTemplateId(mallActivitySpecs.getProfitTemplateId());
                MallProfitTemplate template = mallProfitTemplateService.getById(mallActivitySpecs.getProfitTemplateId());
                if (Objects.nonNull(template)) {
                    adminMallOrderProductDetailsVO.setProfitTemplateName(template.getTemplateName());
                }
            }
            return adminMallOrderProductDetailsVO;

        }).collect(Collectors.toList());

        adminOrderDetailsVO.setProductList(productList);

        adminOrderDetailsVO.setUserRealName(order.getUserRealName());
        adminOrderDetailsVO.setUserTel(order.getUserTel());
        adminOrderDetailsVO.setUserAddr(StrUtil.format("{},{},{},{}", order.getProvince(), order.getCity(), order.getArea(), order.getUserAddress()));
        adminOrderDetailsVO.setRealPrice(order.getRealPrice());
        adminOrderDetailsVO.setCreateTime(order.getCreateTime());
        //上级手机号
        adminOrderDetailsVO.setPushStraightIncomeUserTel(StrUtil.EMPTY);
        adminOrderDetailsVO.setPushBetweenIncomeUserTel(StrUtil.EMPTY);
//        if(ObjectUtil.isNull(order.getPushStraightIncomeUserId()) && order.getPushStraightIncomeUserId() !=0L){
//            UserInfo byId = userInfoDao.getById(order.getPushStraightIncomeUserId());
//            adminOrderDetailsVO.setPushStraightIncomeUserTel(byId.getUserTel());
//        }
//        if(ObjectUtil.isNull(order.getPushStraightIncomeUserId()) && order.getPushStraightIncomeUserId() !=0L){
//            UserInfo byId = userInfoDao.getById(order.getPushBetweenIncomeUserId());
//            adminOrderDetailsVO.setPushBetweenIncomeUserTel(byId.getUserTel());
//        }

        UserInfo user = userInfoDao.getById(order.getUserId());
        if (ObjectUtil.isNotNull(user.getRecommendUserId()) && user.getRecommendUserId() != 0L) {
            UserInfo pushStraightIncomeUser = userInfoDao.getById(user.getRecommendUserId());
            if (ObjectUtil.isNotNull(pushStraightIncomeUser)) {
                adminOrderDetailsVO.setPushStraightIncomeUserTel(pushStraightIncomeUser.getUserTel());
                if (ObjectUtil.isNotNull(pushStraightIncomeUser.getRecommendUserId()) && pushStraightIncomeUser.getRecommendUserId() != 0L) {
                    UserInfo pushBetweenIncomeUser = userInfoDao.getById(pushStraightIncomeUser.getRecommendUserId());
                    adminOrderDetailsVO.setPushBetweenIncomeUserTel(pushBetweenIncomeUser.getUserTel());
                }

            }
        }

        UserInfo byId = userInfoDao.getById(order.getUserId());
        adminOrderDetailsVO.setBuyerUserTel(byId.getUserTel());


        //兑换订单
        if (order.getActivityType() == ActivityTypeEnum.EXCHANGE) {
            List<MallOrderExchange> exchangeList = mallOrderExchangeDao.getOrderExchangeListByOrderId(order.getId());
            List<OrderExchangeVO> costExchangeList = exchangeList.stream().map(exchange -> {
                return BeanUtil.copyProperties(exchange, OrderExchangeVO.class);
            }).collect(Collectors.toList());
            adminOrderDetailsVO.setExchangeList(costExchangeList);
        }
        if (Objects.nonNull(order.getCouponAmount()) && BigDecimalUtils.greaterZero(order.getCouponAmount())) {
            UserCoupons userCoupons = userCouponsService.getByOrderId(order.getId());
            if (Objects.nonNull(userCoupons)) {
                adminOrderDetailsVO.setCouponsTitle(userCoupons.getTitle());
                adminOrderDetailsVO.setCouponAmount(order.getCouponAmount());
                adminOrderDetailsVO.setCouponsType(userCoupons.getCouponsType());
                adminOrderDetailsVO.setActivityCouponsId(userCoupons.getActivityCouponsId());
                adminOrderDetailsVO.setFullMoney(userCoupons.getFullMoney());
                adminOrderDetailsVO.setMoney(userCoupons.getMoney());
                adminOrderDetailsVO.setProportion(userCoupons.getProportion());
            }
        }
        return adminOrderDetailsVO;
    }

    @Override
    @Deprecated
    public Page<AdminPageRefundOrderVO> adminPageRefundOrder(String orderNo, String userTel, Integer refundStatus, Integer pageNo, Integer pageSize, Long supplierId) {
        return mallOrderDao.adminPageRefundOrder(orderNo, userTel, refundStatus, pageNo, pageSize, supplierId);
    }

    // todo：需要更改
    @Override
    public AdminRefundDetailsVO adminRefundDetails(Long orderId) {
        MallOrder order = mallOrderDao.getById(orderId);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        AdminRefundDetailsVO adminRefundDetailsVO = BeanUtil.copyProperties(order, AdminRefundDetailsVO.class);

        List<MallOrderProduct> list = mallOrderProductService.getListByOrderId(orderId);
        Assert.isFalse(list.size() == 0, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_PRODUCT_DOES_NOT_EXIST));
        List<AdminRefundProductDetails> productList = list.stream().map(mallOrderProduct -> {


            MallProduct mallProduct = mallProductService.getById(mallOrderProduct.getProductId());
            AdminRefundProductDetails adminRefundProductDetails = BeanUtil.copyProperties(mallOrderProduct, AdminRefundProductDetails.class);
            adminRefundProductDetails.setRefundPrice(mallOrderProduct.getProductSalesPrice().multiply(new BigDecimal(mallOrderProduct.getRefundNum())));
            adminRefundProductDetails.setProductCode(ObjectUtil.isNull(mallProduct) ? StrUtil.EMPTY : mallProduct.getProductCode());


            return adminRefundProductDetails;
        }).collect(Collectors.toList());
        adminRefundDetailsVO.setProductList(productList);

        UserInfo user = userInfoDao.getById(order.getUserId());
        adminRefundDetailsVO.setUserTel(user.getUserTel());

        //申请时间
        MallOrderStatusLog statusLog = mallOrderStatusLogService.getOneByOrderIdAndChangeType(orderId, MallOrderRefundStatusEnum.APPLYING.name());
        adminRefundDetailsVO.setApplyTime(ObjectUtil.isNull(statusLog) ? DateTime.now() : statusLog.getCreateTime());
        adminRefundDetailsVO.setImgHost(staticDataDao.getByType("imgHost").getValue());

        return adminRefundDetailsVO;
    }

    // todo：需要修改
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approvalRefundSuccess(Long orderId, Long orderProductId, String ip) {
        MallOrder order = mallOrderDao.getById(orderId);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));

        MallOrderProduct mallOrderProduct = mallOrderProductService.getById(orderProductId);
        Assert.notNull(mallOrderProduct, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_PRODUCT_DOES_NOT_EXIST));


        MallPayOrderRecord oldPayOrderRecord = mallPayOrderRecordService.getPaySuccessByOrderNo(order.getOrderNo());

        MallPayOrderRecord newPayOrderRecord = new MallPayOrderRecord();
        newPayOrderRecord.setOrderType(PayTypeEnum.REFUND);
        newPayOrderRecord.setReqTime(DateTime.now());
        newPayOrderRecord.setOrderNo(order.getOrderNo());
        newPayOrderRecord.setUserId(order.getUserId());
        newPayOrderRecord.setPayAmount(order.getRealPrice());
        newPayOrderRecord.setRefundAmount(order.getRefundPrice());
        newPayOrderRecord.setChannel(oldPayOrderRecord.getChannel());
        newPayOrderRecord.setStatus(PayStatusEnum.INIT);
        newPayOrderRecord.setTradeNo(UUID.fastUUID().toString().replaceAll("-", ""));
        newPayOrderRecord.setCloseTime(DateUtil.offsetDay(DateTime.now(), 3));
        newPayOrderRecord.setReqIp(ip);
        MallOrderStatusLog mallOrderStatusLog = new MallOrderStatusLog();
        mallOrderStatusLog.setMallOrderId(order.getId());


        String result = null;
        if (oldPayOrderRecord.getPayType() == PayMethodEnum.FAST_PAY || oldPayOrderRecord.getPayType() == PayMethodEnum.SAND_BALANCE_PAY) {//杉德
            //退款回调地址
            newPayOrderRecord.setNotifyUrl(SandConfig.MALL_REFUND_NOTIFY_URL);
            newPayOrderRecord.setPayType(PayMethodEnum.FAST_PAY);
            JSONObject jsonObject = SandPayUtil.refundRequest(newPayOrderRecord, oldPayOrderRecord.getTradeNo(), order.getRefundReasonWap());
            newPayOrderRecord.setReqResult(jsonObject.toJSONString());
            if (!StrUtil.equals(jsonObject.getJSONObject("head").getString("respCode"), "000000")) {
                throw new GlobalRunTimeException("退款失败:" + jsonObject.getJSONObject("head").getString("respMsg"));
            }

            order.setRefundStatus(MallOrderRefundStatusEnum.REFUNDING);
            order.setRefundReasonTime(DateTime.now());
            mallOrderStatusLog.setChangeType(MallOrderRefundStatusEnum.REFUNDING.name());
            mallOrderStatusLog.setChangeMessage(MallOrderRefundStatusEnum.REFUNDING.getDescription());
            mallOrderStatusLog.setIsRefund(Boolean.TRUE);
            mallOrderStatusLog.setRemark("等待到账，退款金额原路退回");


        } else if (oldPayOrderRecord.getPayType() == PayMethodEnum.HF_FAST_PAY) {//汇付
            JSONObject refund = hfPayHelper.refund(newPayOrderRecord.getUserId(), oldPayOrderRecord.getTradeNo(), newPayOrderRecord.getTradeNo(), oldPayOrderRecord.getPayTime(), newPayOrderRecord.getRefundAmount(), null, null);
            newPayOrderRecord.setReqResult(refund.toJSONString());
            newPayOrderRecord.setNotifyUrl(HfConfig.mallRefundNotifyUrl);
            newPayOrderRecord.setPayType(PayMethodEnum.HF_FAST_PAY);
            order.setRefundStatus(MallOrderRefundStatusEnum.REFUNDING);
            order.setRefundReasonTime(DateTime.now());

            mallOrderStatusLog.setChangeType(MallOrderRefundStatusEnum.REFUNDING.name());
            mallOrderStatusLog.setChangeMessage(MallOrderRefundStatusEnum.REFUNDING.getDescription());
            mallOrderStatusLog.setIsRefund(Boolean.TRUE);
            mallOrderStatusLog.setRemark("等待到账，退款金额原路退回");

        } else if (oldPayOrderRecord.getPayType() == PayMethodEnum.LL_PAY) {//连连
            UserInfo user = userInfoDao.getById(newPayOrderRecord.getUserId());
            String amount = newPayOrderRecord.getRefundAmount().setScale(2, BigDecimal.ROUND_DOWN).toPlainString();
            JSONObject refund = llPayHelper.refundMall(user, oldPayOrderRecord.getTradeNo(), OrderNoUtil.getOrderNo(), amount, LlConfig.mallLlRefundNotifyUrl);
            newPayOrderRecord.setReqResult(refund.toJSONString());
            newPayOrderRecord.setNotifyUrl(LlConfig.mallLlRefundNotifyUrl);
            newPayOrderRecord.setPayType(PayMethodEnum.LL_PAY);
            newPayOrderRecord.setTradeNo(refund.getString("accp_txno"));
            order.setRefundStatus(MallOrderRefundStatusEnum.REFUNDING);
            order.setRefundReasonTime(DateTime.now());

            mallOrderStatusLog.setChangeType(MallOrderRefundStatusEnum.REFUNDING.name());
            mallOrderStatusLog.setChangeMessage(MallOrderRefundStatusEnum.REFUNDING.getDescription());
            mallOrderStatusLog.setIsRefund(Boolean.TRUE);
            mallOrderStatusLog.setRemark("等待到账，退款金额原路退回");

        } else if (oldPayOrderRecord.getPayType() == PayMethodEnum.WALLET_PAY) {//钱包支付
            UserWallet userWallet = userWalletDao.getByUserId(order.getUserId());
            newPayOrderRecord.setPayType(PayMethodEnum.WALLET_PAY);
            newPayOrderRecord.setNotifyUrl(SandConfig.FAST_RETURN_URL);
            newPayOrderRecord.setCloseTime(DateTime.now());
            if (order.getPayWalletPrice().compareTo(BigDecimal.ZERO) == 1) {
                //退款金额
                BigDecimal refundAmount = order.getPayWalletPrice().divide(Convert.toBigDecimal(mallOrderProduct.getProductNum()), 2, BigDecimal.ROUND_DOWN).multiply(Convert.toBigDecimal(mallOrderProduct.getRefundNum()));
                if (refundAmount.compareTo(BigDecimal.ZERO) == 1) {
                    userWalletDao.addBalance(order.getUserId(), refundAmount);

                    UserWalletDetail userWalletDetail = new UserWalletDetail();
                    userWalletDetail.setUserId(order.getUserId());
                    userWalletDetail.setType(WalletDetailTypeEnum.IP_MALL_ORDER_REFUND);
                    userWalletDetail.setAmount(refundAmount);
                    userWalletDetail.setCharge(BigDecimal.ZERO);
                    userWalletDetail.setRealAmount(refundAmount);
                    userWalletDetail.setAfterBalance(userWallet.getBalance().add(refundAmount));
                    userWalletDetail.setBeforeBalance(userWallet.getBalance());
                    userWalletDetail.setIsAdd(Boolean.TRUE);
                    userWalletDetail.setBalanceType(UserBalanceTypeEnum.BALANCE);
                    userWalletDetailDao.insert(userWalletDetail);

                    ExpenditureRecord expenditureRecord = new ExpenditureRecord();
                    expenditureRecord.setUserId(order.getUserId());
                    expenditureRecord.setAmount(refundAmount);
                    expenditureRecord.setCharge(BigDecimal.ZERO);
                    expenditureRecord.setRealAmount(refundAmount);
                    expenditureRecord.setType(ExpenditureRecordTypeEnum.IP_MALL_REFUND);
                    expenditureRecord.setBeforeBalance(userWallet.getBalance());
                    expenditureRecord.setAfterBalance(userWallet.getBalance().add(refundAmount));
                    expenditureRecord.setRemark(order.getOrderNo() + ExpenditureRecordTypeEnum.IP_MALL_REFUND.getDescription());
                    expenditureRecordDao.insert(expenditureRecord);
                }
            }
            if (order.getPayBalancePrice().compareTo(BigDecimal.ZERO) == 1) {
                BigDecimal refundAmount = order.getPayBalancePrice().divide(Convert.toBigDecimal(mallOrderProduct.getProductNum()), 2, BigDecimal.ROUND_DOWN).multiply(Convert.toBigDecimal(mallOrderProduct.getRefundNum()));
                if (refundAmount.compareTo(BigDecimal.ZERO) == 1) {
                    userWalletDao.addPayBalance(order.getUserId(), refundAmount);

                    UserWalletDetail userWalletDetail = new UserWalletDetail();
                    userWalletDetail.setUserId(order.getUserId());
                    userWalletDetail.setType(WalletDetailTypeEnum.IP_MALL_ORDER_REFUND);
                    userWalletDetail.setAmount(refundAmount);
                    userWalletDetail.setCharge(BigDecimal.ZERO);
                    userWalletDetail.setRealAmount(refundAmount);
                    userWalletDetail.setAfterBalance(userWallet.getPayBalance().add(refundAmount));
                    userWalletDetail.setBeforeBalance(userWallet.getPayBalance());
                    userWalletDetail.setIsAdd(Boolean.TRUE);
                    userWalletDetail.setBalanceType(UserBalanceTypeEnum.PAY_BALANCE);
                    userWalletDetailDao.insert(userWalletDetail);

                    ExpenditureRecord expenditureRecord = new ExpenditureRecord();
                    expenditureRecord.setUserId(order.getUserId());
                    expenditureRecord.setAmount(refundAmount);
                    expenditureRecord.setCharge(BigDecimal.ZERO);
                    expenditureRecord.setRealAmount(refundAmount);
                    expenditureRecord.setType(ExpenditureRecordTypeEnum.IP_MALL_REFUND);
                    expenditureRecord.setBeforeBalance(userWallet.getPayBalance());
                    expenditureRecord.setAfterBalance(userWallet.getPayBalance().add(refundAmount));
                    expenditureRecord.setRemark(order.getOrderNo() + ExpenditureRecordTypeEnum.IP_MALL_REFUND.getDescription());
                    expenditureRecordDao.insert(expenditureRecord);
                }
            }

            if (order.getWishBalancePrice().compareTo(BigDecimal.ZERO) == 1) {
                BigDecimal refundAmount = order.getWishBalancePrice().divide(Convert.toBigDecimal(mallOrderProduct.getProductNum()), 2, BigDecimal.ROUND_DOWN).multiply(Convert.toBigDecimal(mallOrderProduct.getRefundNum()));
                if (refundAmount.compareTo(BigDecimal.ZERO) == 1) {
                    userWalletDao.addWishBalance(order.getUserId(), refundAmount);

                    UserWalletDetail userWalletDetail = new UserWalletDetail();
                    userWalletDetail.setUserId(order.getUserId());
                    userWalletDetail.setType(WalletDetailTypeEnum.IP_MALL_ORDER_REFUND);
                    userWalletDetail.setAmount(refundAmount);
                    userWalletDetail.setCharge(BigDecimal.ZERO);
                    userWalletDetail.setRealAmount(refundAmount);
                    userWalletDetail.setAfterBalance(userWallet.getWishBalance().add(refundAmount));
                    userWalletDetail.setBeforeBalance(userWallet.getWishBalance());
                    userWalletDetail.setIsAdd(Boolean.TRUE);
                    userWalletDetail.setBalanceType(UserBalanceTypeEnum.WISH_BALANCE);
                    userWalletDetailDao.insert(userWalletDetail);

                    ExpenditureRecord expenditureRecord = new ExpenditureRecord();
                    expenditureRecord.setUserId(order.getUserId());
                    expenditureRecord.setAmount(refundAmount);
                    expenditureRecord.setCharge(BigDecimal.ZERO);
                    expenditureRecord.setRealAmount(refundAmount);
                    expenditureRecord.setType(ExpenditureRecordTypeEnum.IP_MALL_REFUND);
                    expenditureRecord.setBeforeBalance(userWallet.getWishBalance());
                    expenditureRecord.setAfterBalance(userWallet.getWishBalance().add(refundAmount));
                    expenditureRecord.setRemark(order.getOrderNo() + ExpenditureRecordTypeEnum.IP_MALL_REFUND.getDescription());
                    expenditureRecordDao.insert(expenditureRecord);
                }
            }
            //支付订单状态
            newPayOrderRecord.setStatus(PayStatusEnum.SUCCESS);
            //退款状态
            order.setRefundStatus(MallOrderRefundStatusEnum.REFUND_SUCCES);


            mallOrderStatusLog.setChangeType(MallOrderRefundStatusEnum.REFUND_SUCCES.name());
            mallOrderStatusLog.setChangeMessage(MallOrderRefundStatusEnum.REFUND_SUCCES.getDescription());
            mallOrderStatusLog.setIsRefund(Boolean.TRUE);
            mallOrderStatusLog.setRemark("退款金额已原路退还到你的账户");


            //处理订单商品退款状态
            mallOrderProduct.setRefundSuccessCount(mallOrderProduct.getRefundNum());
            mallOrderProduct.updateById();

            //判断订单是否全部退款
            List<MallOrderProduct> orderProductList = mallOrderProductService.getListByOrderId(order.getId());
            //商品售后退款成功总数
            int sumRefundSuccessCount = orderProductList.stream().mapToInt(orderProduct -> Objects.isNull(orderProduct.getRefundSuccessCount()) ? 0 : orderProduct.getRefundSuccessCount()).sum();
            //商品购买总数
            int sumProductNum = orderProductList.stream().mapToInt(orderProduct -> Objects.isNull(orderProduct.getProductNum()) ? 0 : orderProduct.getProductNum()).sum();
            if (sumProductNum <= sumRefundSuccessCount) {
                order.setStatus(MallOrderStatusEnum.CLOSURE);
                order.updateById();
            }

            //收益处理
            List<MallOrderIncome> orderIncomeList = mallOrderIncomeDao.getListByOrderId(order.getId());
            if (orderIncomeList.size() > 0) {
                //如果退款金额大于等于订单金额，那么收益全部失效
                if (order.getRefundPrice().compareTo(order.getRealPrice()) > -1) {
                    for (MallOrderIncome mallOrderIncome : orderIncomeList) {
                        mallOrderIncome.setCancelIncomePrice(mallOrderIncome.getIncomeNum());
                        mallOrderIncome.setIncomeStatus(MallOrderIncomeTypeEnum.EXPIRED);
                        mallOrderIncome.setIsEfficient(Boolean.FALSE);
                        mallOrderIncome.updateById();
                    }
                } else {//只退了一部分商品
                    for (MallOrderIncome mallOrderIncome : orderIncomeList) {
                        MallOrderProduct orderProduct = mallOrderProductService.getOneByOrderIdAndOrderProductId(orderId, orderProductId);
                        BigDecimal productCostPrice = orderProduct.getProductCostPrice();
                        BigDecimal productSalesPrice = orderProduct.getProductSalesPrice();
                        //退款的收益金额 = (商品售价 - 商品成本价 ) * 退款数量
                        BigDecimal multiply = productSalesPrice.subtract(productCostPrice).multiply(Convert.toBigDecimal(orderProduct.getRefundNum()));
                        //基数 - 退款金额 = 剩余收益
                        BigDecimal subtract = mallOrderIncome.getIncomeCardinality().subtract(multiply);
                        //到账的收益 = 剩余收益 * 收益比例
                        BigDecimal realIncomePrice = subtract.multiply(mallOrderIncome.getIncomeProportion()).setScale(2, BigDecimal.ROUND_DOWN);
                        BigDecimal cancelIncomePrice = mallOrderIncome.getIncomeNum().subtract(realIncomePrice);
                        //真实到账的收益
                        mallOrderIncome.setRealIncomePrice(realIncomePrice);
                        mallOrderIncome.setIsEfficient(Boolean.TRUE);
                        //失效的收益
                        mallOrderIncome.setCancelIncomePrice(cancelIncomePrice);
                        mallOrderIncome.updateById();
                    }
                }
            }
        } else {
            throw new GlobalRunTimeException("不支持的支付方式");
        }

        order.updateById();
        newPayOrderRecord.insert();
        mallOrderStatusLog.insert();
        if (StrUtil.isNotBlank(order.getSupplyOrderNo())) {
            smartSupplyHelper.afterSales(order, mallOrderProduct.getRefundSuccessCount());
        }
    }

    @Override
    public Boolean updateIncomeUserId(Long id, Long pushStraightIncomeUserId, Long pushBetweenIncomeUserId, Long cityServerIncomeUserId) {
        return mallOrderDao.updateIncomeUserId(id, pushStraightIncomeUserId, pushBetweenIncomeUserId, cityServerIncomeUserId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void postLogic(MallOrderStatusLog mallOrderStatusLog, MallOrder order) {

        if (order.getActivityType() == ActivityTypeEnum.SALES) {

            GetMallOrderGrossProfitDTO grossProfitByOrderId = getGrossProfitByOrderId(order);
//
//        if (grossProfitByOrderId.getGrossProfit().compareTo(BigDecimal.ZERO) == 1) { //大于0
//            //任务完成
//            //统计瓜分活动的奖池
//            carveUpPoolService.addMallOrderPrizeDrawActivityPoolAmountLog(order.getId(), grossProfitByOrderId.getGrossProfit(), grossProfitByOrderId.getLinkId());
//        }
            if (NumberUtil.isGreater(grossProfitByOrderId.getRealPrice(), BigDecimal.ZERO) && order.getRefundStatus() == MallOrderRefundStatusEnum.NEW_NOT_APPLY) {
                activityTaskService.finishTask(null, order.getUserId(), 0, grossProfitByOrderId.getRealPrice(), ActivityTaskTypeEnum.TOTAL_SPEND, LinkTypeEnums.MALL, order.getId(), true);
                List<MallOrderProduct> mallOrderProducts = mallOrderProductService.getListByOrderId(order.getId());
                for (MallOrderProduct mallOrderProduct : mallOrderProducts) {
                    MallProduct mallProduct = mallProductService.getById(mallOrderProduct.getProductId());

                    if (mallProduct.getType() == ProductTypeEnum.GIFT) {
                        continue;
                    }
                    BigDecimal couponAmount = BigDecimal.ZERO;
                    if (Objects.nonNull(order.getCouponAmount())) {
                        couponAmount = order.getCouponAmount();
                    }
                    taskService.finishTask(userInfoDao.getById(order.getUserId()), TaskOrderTypeEnum.MALL, TaskTypeEnum.TOTAL_SPEND, order.getId(), mallProduct.getId(), mallOrderProduct.getProductSalesPrice().multiply(BigDecimal.valueOf(mallOrderProduct.getProductNum())).subtract(couponAmount));
                    taskService.finishTask(userInfoDao.getById(order.getUserId()), TaskOrderTypeEnum.MALL, TaskTypeEnum.TOTAL_BUY, order.getId(), mallProduct.getId(), mallOrderProduct.getProductSalesPrice().multiply(BigDecimal.valueOf(mallOrderProduct.getProductNum())).subtract(couponAmount));
                }
            }
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    if (NumberUtil.isGreater(grossProfitByOrderId.getRealPrice(), BigDecimal.ZERO) && order.getRefundStatus() == MallOrderRefundStatusEnum.NEW_NOT_APPLY) {
                        List<MallOrderProduct> mallOrderProducts = mallOrderProductService.getListByOrderId(order.getId());
                        for (MallOrderProduct mallOrderProduct : mallOrderProducts) {
                            SaasTaskBurialPointDTO saasTaskBurialPointDTO = new SaasTaskBurialPointDTO();
                            // 支付成功后.发送任务判定.
                            messageQueueHelper.sendMessage(MessageTopic.DISK_TAKER, saasTaskBurialPointDTO.wallet(order.getUserId(), SaasTaskTypeEnum.PURCHASE_SPECIFIED_IP_ITEMS, order.getRealPrice(), 0, mallOrderProduct.getProductId(), order.getId()), SaasTaskTypeEnum.PURCHASE_SPECIFIED_IP_ITEMS.name());
                            // 累计消费
                            messageQueueHelper.sendMessage(MessageTopic.DISK_TAKER, saasTaskBurialPointDTO.wallet(order.getUserId(), SaasTaskTypeEnum.ACCUMULATED_CONSUMPTION_AMOUNT, order.getRealPrice(), 0, mallOrderProduct.getProductId(), order.getId(), SaasTaskMeetConditionsLocationEnum.MALL), SaasTaskTypeEnum.ACCUMULATED_CONSUMPTION_AMOUNT.name(), order.getOrderNo());
                        }
                    }
                }
            });
        }
        //修改为已结算
        mallOrderStatusLogDao.updateIsSettleByOrderId(mallOrderStatusLog.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void miniPostLogic(MallOrderStatusLog mallOrderStatusLog, MallOrder order) {
        mallOrderStatusLogDao.updateIsSettleByOrderId(mallOrderStatusLog.getId());
        Result<Boolean> result = wxMiniUserPointsClient.thawPoints(PointsReq.buildBuyUnLock(order.getId()));
        if (!ErrorCode.SUCCESS.getCode().equals(result.getCode()) || !result.getData()) {
            throw new GlobalRunTimeException("解冻积分失败");
        }
    }

    @Override
    public GetMallOrderGrossProfitDTO getGrossProfitByOrderId(MallOrder mallOrder) {
        GetMallOrderGrossProfitDTO getMallOrderGrossProfitDTO = new GetMallOrderGrossProfitDTO();
        BigDecimal couponAmount = BigDecimal.ZERO;
        if (Objects.nonNull(mallOrder.getCouponAmount())) {
            couponAmount = mallOrder.getCouponAmount();
        }
        List<MallOrderProduct> orderProductList = mallOrderProductService.getListByOrderId(mallOrder.getId());
        BigDecimal realPrice = BigDecimal.ZERO;
        Long linkId = 0L;
        for (MallOrderProduct mallOrderProduct : orderProductList) {
            MallProduct mallProduct = mallProductService.getById(mallOrderProduct.getProductId());
            if (ObjectUtil.isNotNull(mallProduct) && mallProduct.getType() == ProductTypeEnum.MATERIAL) {
                //利润
                BigDecimal profit = mallOrderProduct.getProductSalesPrice().subtract(mallOrderProduct.getProductCostPrice());
                //总利润 = 利润 *数量
                BigDecimal grossProfit = profit.multiply(Convert.toBigDecimal(mallOrderProduct.getProductNum() - mallOrderProduct.getRefundNum()));
                //计算的价格
                realPrice = realPrice.add(grossProfit);
                getMallOrderGrossProfitDTO.setRealPrice(getMallOrderGrossProfitDTO.getRealPrice().add(mallOrderProduct.getProductSalesPrice().multiply(Convert.toBigDecimal(mallOrderProduct.getProductNum() - mallOrderProduct.getRefundNum()))));

                if (linkId.intValue() == 0L) {//取第一个活动id
                    linkId = mallOrderProduct.getActivityId();
                }
            }
        }
        realPrice = realPrice.subtract(couponAmount);
        getMallOrderGrossProfitDTO.setGrossProfit(realPrice);
        getMallOrderGrossProfitDTO.setLinkId(linkId);
        return getMallOrderGrossProfitDTO;
    }

    @Override
    public void editAdminNote(Long id, String adminNote) {
        MallOrder order = mallOrderDao.getById(id);
        Assert.isTrue(ObjectUtil.isNotNull(order), () -> new GlobalRunTimeException("订单不存在"));
        Assert.isTrue(mallOrderDao.editAdminNoteById(id, adminNote), () -> new GlobalRunTimeException("修改失败"));
    }

    @Override
    public List<ExportOrderListVO> exportOrderList(ActivityTypeEnum type) {
        return mallOrderDao.exportOrderList(type);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<BatchDeliverDTO> batchDeliver(MultipartFile file) throws IOException {
        List<BatchDeliverDTO> cachedDataList = new ArrayList<>();
        //1.获取工作簿
        ExcelReaderBuilder readBook = null;
        readBook = EasyExcel.read(file.getInputStream(), BatchDeliverDTO.class, new ReadListener<BatchDeliverDTO>() {

            @Override
            public void invoke(BatchDeliverDTO o, AnalysisContext analysisContext) {
                cachedDataList.add(o);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {

            }
        });
        //2.获取sheet
        ExcelReaderSheetBuilder sheet = readBook.sheet();
        //3.获取Excel中的数据
        List<BatchDeliverDTO> batchDelivers = sheet.doReadSync();
        List<BatchDeliverDTO> list = new ArrayList<>();
        batchDelivers.forEach(batchDeliverDTO -> {
            // 先验证所有的数据,发货
            if (StrUtil.isBlank(batchDeliverDTO.getExpressNumber())) {
                list.add(batchDeliverDTO);
                return;
            }
            //快递公司不能为空
            if (StrUtil.isBlank(batchDeliverDTO.getExpressCompany())) {
                list.add(batchDeliverDTO);
                return;
            }
            //商品数量不能小于0
            if (Long.parseLong(batchDeliverDTO.getProductNumber()) <= 0) {
                list.add(batchDeliverDTO);
                return;
            }
            MallOrder byOrderIdAndExpressNumber = mallOrderDao.byOrderIdAndExpressNumber(batchDeliverDTO.getOrderId());
            if (BeanUtil.isEmpty(byOrderIdAndExpressNumber)) {
                list.add(batchDeliverDTO);
                return;
            }
            batchDeliverDTO.setId(byOrderIdAndExpressNumber.getId());
        });
        if (CollUtil.isNotEmpty(list)) {
            return list;
        }

        // 发货
        batchDelivers.forEach(batchDeliverDTO -> {
            MallOrder order = mallOrderDao.getByOrderNo(batchDeliverDTO.getOrderId());
            Assert.notNull(order, () -> new GlobalRunTimeException("订单不存在"));
            ship(order, batchDeliverDTO.getExpressNumber(), batchDeliverDTO.getExpressCompany());
        });
        return list;
    }

    @Override
    public List<MallOrder> getByRefundStatus(MallOrderRefundStatusEnum mallOrderRefundStatusEnum) {
        return mallOrderDao.getByRefundStatus(mallOrderRefundStatusEnum);
    }

    /**
     * 获取订单列表
     *
     * @param ids
     * @return
     */
    @Override
    public List<MallOrder> getByIds(List<Long> ids, Long wxMiniUserId) {
        return mallOrderDao.getWxMiniOrderByIds(ids, wxMiniUserId);
    }

    /**
     * 获取分销订单
     *
     * @param orderNO
     * @param startTime
     * @param endTime
     * @param miniUserTel
     * @param status
     * @param incomeStatus
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public Page<DistributionOrderVO> getDistributionOrderVOAdminPage(String orderNO, Date startTime, Date endTime, String miniUserTel, MallOrderStatusEnum status, MallOrderIncomeTypeEnum incomeStatus, Integer pageNo, Integer pageSize) {
        return mallOrderDao.getDistributionOrderVOAdminPage(orderNO, startTime, endTime, miniUserTel, status, incomeStatus, pageNo, pageSize);
    }


    private MallOrderProduct checkRefundOrder(MallOrder order, Long orderProductId) {
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        MallOrderProduct mallOrderProduct = mallOrderProductService.getById(orderProductId);
        Assert.notNull(mallOrderProduct, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_PRODUCT_DOES_NOT_EXIST));
        //判断订单状态是否是可退款状态
        Assert.isTrue(MallOrderStatusEnum.getIsRefundStatus().contains(order.getStatus()), () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_STATUS_ERROR));

        if (order.getStatus() == MallOrderStatusEnum.FINISH) {//如果是已完成状态下 则判断是否超过7天
            MallOrderStatusLog mallOrderStatusLog = mallOrderStatusLogService.getOneByOrderIdAndChangeType(order.getId(), MallOrderStatusEnum.FINISH.toString());
            DateTime dateTime = DateUtil.offsetDay(mallOrderStatusLog.getCreateTime(), 7);
            Assert.isTrue(dateTime.isAfter(DateTime.now()), () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_REFUND_TIME_OUT));
        }
        Assert.isTrue(order.getId().intValue() == mallOrderProduct.getMallOrderId().intValue(), () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_PRODUCT_DOES_NOT_EXIST));
        if (order.getIsVirtual()) {
            // 虚拟订单 只有当直充订单充值失败才可申请售后
            ApiOrderDirect apiOrderDirect = apiOrderDirectService.getByOrderId(order.getId());
            if (!"failed".equals(apiOrderDirect.getApiOrderState())) {
                new GlobalRunTimeException(ErrorCode.VIRTUAL_ORDERS_CANNOT_BE_INITIATED_AFTER_SALES);
            }
        }
        return mallOrderProduct;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void ship(MallOrder order, String deliveryNo, String deliveryName) {
        //确认订单
        Assert.isTrue(order.getStatus() == MallOrderStatusEnum.WAIT_RECEIPT, () -> new GlobalRunTimeException("订单状态不正确"));
        //更新订单状态,物流单号,物流公司
        Assert.isTrue(mallOrderDao.updateStatusAndDeliveryNoAndDeliveryNameById(order.getId(), MallOrderStatusEnum.TO_BE_RECEIPT, deliveryNo, deliveryName), () -> new GlobalRunTimeException("发货失败"));
        //日志
        MallOrderStatusLog mallOrderStatusLog = new MallOrderStatusLog();
        mallOrderStatusLog.setMallOrderId(order.getId());
        mallOrderStatusLog.setChangeType(MallOrderStatusEnum.TO_BE_RECEIPT.toString());
        mallOrderStatusLog.setChangeMessage(MallOrderStatusEnum.TO_BE_RECEIPT.getDescription());
        mallOrderStatusLog.setRemark("发货时间");
        mallOrderStatusLog.insert();
        //region 推送消息
        log.info("商城发货推送 开始-------");
        MallOrderPushDTO mallOrderPushDTO = new MallOrderPushDTO();
        mallOrderPushDTO.setMallOrder(order);
        mallOrderPushService.mallOrderPushMessage(mallOrderPushDTO, MallOrderPushTypeEnum.TO_BE_RECEIPT);
        log.info("商城发货推送 结束-------");
        //endregion
    }


    /**
     * 更换收货地址
     *
     * @param orderId
     * @param mallDeliveryAddressId
     * @param userId
     * @param source
     * @param wxMiniUserId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateMallDeliveryAddressVO updateMallDeliveryAddress(Long orderId, Long mallDeliveryAddressId, Long userId, SourceEnum source, Long wxMiniUserId) {
        MallOrder order = mallOrderDao.getOrderByIdAndUserId(orderId, userId, source, wxMiniUserId);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        //虚拟订单
        Assert.isFalse(order.getIsVirtual(), () -> new GlobalRunTimeException(ErrorCode.VIRTUAL_ORDER_NOT_UPDATE_DELIVERY_ADDRESS));
        //是否待发货
        Assert.isTrue(order.getStatus() == MallOrderStatusEnum.WAIT_RECEIPT, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_STATUS_ERROR));
        //判断是否接单
        if (order.getIsAccept()) {
            return new UpdateMallDeliveryAddressVO();
        }
        Integer count = mallOrderUpdateAddressLogDao.countByOrderId(orderId);
        Assert.isFalse(count != null && count > 0, () -> new GlobalRunTimeException(ErrorCode.AUDITING_NOT_UPDATE));
        MallDeliveryAddress mallDeliveryAddress = mallDeliveryAddressService.getAddressByUserIdAndId(userId, mallDeliveryAddressId);
        Assert.notNull(mallDeliveryAddress, () -> new GlobalRunTimeException(ErrorCode.MALL_DELIVERY_ADDRESS_DOES_NOT_EXIST));
        Assert.isTrue(mallOrderDao.updateDeliveryAddress(mallDeliveryAddress, order.getId()), () -> new GlobalRunTimeException(ErrorCode.UPDATE_ERROR));
        MallOrderUpdateAddressLog mallOrderUpdateAddressLog = MallOrderUpdateAddressLog.build(order, mallDeliveryAddress, UpdateAddrOperationTypeEnums.USER);
        Assert.isTrue(mallOrderUpdateAddressLogDao.save(mallOrderUpdateAddressLog), () -> new GlobalRunTimeException(ErrorCode.UPDATE_ERROR));
        UpdateMallDeliveryAddressVO updateMallDeliveryAddressVO = new UpdateMallDeliveryAddressVO();
        updateMallDeliveryAddressVO.setSuccess(Boolean.TRUE);
        BeanUtils.copyProperties(mallDeliveryAddress, updateMallDeliveryAddressVO);
        return updateMallDeliveryAddressVO;
    }

    /**
     * 获取当前订单地址
     *
     * @param orderId
     * @return
     */
    @Override
    public MallOrderDeliveryAddressVO orderNowAddress(Long orderId, Long userId, SourceEnum source, Long wxMiniUserId) {
        MallOrder order = mallOrderDao.getOrderByIdAndUserId(orderId, userId, source, wxMiniUserId);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.MALL_ORDER_DOES_NOT_EXIST));
        MallOrderDeliveryAddressVO mallOrderDeliveryAddressVO = new MallOrderDeliveryAddressVO();
        mallOrderDeliveryAddressVO.setRecipientName(order.getUserRealName());
        mallOrderDeliveryAddressVO.setContactNumber(order.getUserTel());
        mallOrderDeliveryAddressVO.setState(order.getProvince());
        mallOrderDeliveryAddressVO.setCity(order.getCity());
        mallOrderDeliveryAddressVO.setArea(order.getArea());
        mallOrderDeliveryAddressVO.setDetailedAddress(order.getUserAddress());
        return mallOrderDeliveryAddressVO;
    }

    private void checkMallProduct(MallActivity mallActivity, MallActivitySpecs mallActivitySpecs, MallProduct mallProduct, MallProductSpecs mallProductSpecs, MallDeliveryAddress mallDeliveryAddress, Integer count, UserInfo user, CheckProductHasPreemptionDTO hasPreemptionDTO) {
        //营销活动是否存在
        Assert.notNull(mallActivity, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_DOES_NOT_EXIST));

        //是否存在待付款的订单
        List<MallOrder> orderList = mallOrderDao.getListByUserIdAndStatus(user.getId(), MallOrderStatusEnum.WAIT_PAY);
        if (orderList.size() > 0) {
            Assert.isFalse(mallActivity.getActivityType() == ActivityTypeEnum.SALES, () -> new GlobalRunTimeException(ErrorCode.WAIT_PAY_ORDER));
        }

        //是否实名
        Assert.isTrue(user.getIsSm(), () -> new GlobalRunTimeException(ErrorCode.USER_NOT_SM));

        //营销活动规格是否存在
        Assert.notNull(mallActivitySpecs, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_SPECIFICATION_DOES_NOT_EXIST));
        //商品信息
        Assert.notNull(mallProduct, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_DOES_NOT_EXIST));
        //商品规格
        Assert.notNull(mallProductSpecs, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_SPECIFICATION_DOES_NOT_EXIST));
        if (ProductTypeEnum.VIRTUAL != mallProduct.getType()) {
            //校验地址
            Assert.notNull(mallDeliveryAddress, () -> new GlobalRunTimeException(ErrorCode.MALL_INCORRECT_ADDRESS));
        }

        //商品是否下架
        Assert.isTrue(mallActivity.getStatus(), () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_IS_NO_LONGER_AVAILABLE));
        //判断是否为优先购状态下,校验开始时间
        DateTime now = DateTime.now();
        if (now.isBefore(mallActivity.getStartTime())) {
            MallMemberCheckHasPreemptionDTO checkHasPreemptionDTO = mallMemberEquityService.checkHasPreemption(user, mallActivitySpecs.getId());
            //优先购泡判断条件 1.有优先购的权限，并且是活动时间之前（正常活动时间倒推至权益设置提前时间的中间）2.可用抢购数量是否充足
            Assert.notNull(checkHasPreemptionDTO, () -> new GlobalRunTimeException(ErrorCode.NOT_BEGIN));
            DateTime checkTime = DateUtil.offsetMinute(mallActivity.getStartTime(), -checkHasPreemptionDTO.getPrioritizeTheLeadTime());
            if (!DateUtil.isIn(now, checkTime, mallActivity.getStartTime())) {
                throw new GlobalRunTimeException(ErrorCode.NOT_BEGIN);
            }
            hasPreemptionDTO.setIsHasPreemption(Boolean.TRUE);
            hasPreemptionDTO.setMallMemberEquityId(checkHasPreemptionDTO.getMallMemberEquityId());
        } else {
            Assert.isTrue(now.isAfter(mallActivity.getStartTime()), () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_IS_NO_LONGER_AVAILABLE));
        }
        //数量不足
        Assert.isTrue(mallActivitySpecs.getUsableStockCount() - count >= 0, () -> new GlobalRunTimeException(ErrorCode.INSUFFICIENT_STOCK));
        //校验购买上限
        Integer userBuyCount = mallOrderProductService.getUserBuyCountByUserIdAndActivityId(user.getId(), mallActivity.getId());
        MallBuyLimitTypeEnum mallBuyLimitTypeEnum = mallActivity.getBuyLimitType();
        MallUserActivitySummary mallUserActivitySummary = mallUserActivitySummaryService.get(user.getId());
        //如果是动态上线
        BuyLimitDTO buyLimitDTO = mallActivityService.convertBuyLimit(mallActivity, mallUserActivitySummary);
        Assert.isTrue(userBuyCount + count <= buyLimitDTO.getBuyLimit(), () -> new GlobalRunTimeException(ErrorCode.MALL_THE_CURRENT_PURCHASE_QUANTITY_HAS_REACHED_THE_UPPER_LIMIT));


        //校验参与对象
        if (mallActivity.getParticipants() == ParticipantsEnum.APPOINT) {//如果是指定NFT
            Long collectionId = mallActivity.getCollectionId();
            //判断id是否为空
            Assert.notNull(collectionId, () -> new GlobalRunTimeException(ErrorCode.COLLECTION_NOT_FOUND));
            //判断id是否为0
            Assert.isFalse(collectionId == 0L, () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_IS_NO_LONGER_AVAILABLE));
            //不满足兑换条件
            Assert.isTrue(userCollectionService.getIsContainsAndIsHoldAndIsOpenAndOnConsignByCollectionId(collectionId, user.getId()) > 0, () -> new GlobalRunTimeException(ErrorCode.DOES_NOT_MEET_THE_REDEMPTION_CONDITIONS));
        }

    }

}